Guest User

Untitled

a guest
Nov 7th, 2019
313
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 44.76 KB | None | 0 0
  1. # deCONZ Bridge
  2. #
  3. # Author: Smanar
  4. #
  5. """
  6. <plugin key="deCONZ" name="deCONZ plugin" author="Smanar" version="1.0.10" wikilink="https://github.com/Smanar/Domoticz-deCONZ" externallink="https://www.dresden-elektronik.de/funktechnik/products/software/pc-software/deconz/?L=1">
  7.    <description>
  8.        <br/><br/>
  9.        <h2>deCONZ Bridge</h2><br/>
  10.        It use the deCONZ rest api to make a bridge beetween your zigbee network and Domoticz (Using Conbee or Raspbee)
  11.        <br/><br/>
  12.        <h3>Remark</h3>
  13.        <ul style="list-style-type:square">
  14.            <li>You can use the file API_KEY.py if you have problems to get your API Key or your Websocket Port</li>
  15.            <li>You can find updated files for deCONZ on their github : https://github.com/dresden-elektronik/deconz-rest-plugin</li>
  16.            <li>If you want the plugin works without connexion, use as IP 127.0.0.1 (if deCONZ and domoticz are on same machine)</li>
  17.            <li>If you are running the plugin for the first time, better to enable debug log (Take Debug info Only)</li>
  18.        </ul>
  19.        <h3>Supported Devices</h3>
  20.        <ul style="list-style-type:square">
  21.            <li>https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/Supported-Devices</li>
  22.        </ul>
  23.        <h3>Configuration</h3>
  24.        Gateway configuration
  25.    </description>
  26.    <params>
  27.        <param field="Address" label="deCONZ IP" width="150px" required="true" default="127.0.0.1"/>
  28.        <param field="Port" label="Port" width="150px" required="true" default="80"/>
  29.        <param field="Mode2" label="API KEY" width="75px" required="true" default="1234567890" />
  30.        <param field="Mode3" label="Debug" width="150px">
  31.            <options>
  32.                <option label="None" value="0"  default="true" />
  33.                <option label="Debug info Only" value="2"/>
  34.                <option label="Basic Debugging" value="62"/>
  35.                <option label="Basic+Messages" value="126"/>
  36.                <option label="Connections Only" value="16"/>
  37.                <option label="Connections+Python" value="18"/>
  38.                <option label="Connections+Queue" value="144"/>
  39.                <option label="All" value="-1"/>
  40.            </options>
  41.        </param>
  42.    </params>
  43. </plugin>
  44. """
  45.  
  46. # All imports
  47. import Domoticz
  48.  
  49. import json,urllib, time
  50.  
  51. REQUESTPRESENT = True
  52. try:
  53.     import requests
  54. except:
  55.     REQUESTPRESENT = False
  56.  
  57. from fonctions import rgb_to_xy, rgb_to_hsl, xy_to_rgb
  58. from fonctions import Count_Type, ProcessAllState, ProcessAllConfig, First_Json, JSON_Repair, get_JSON_payload
  59. from fonctions import ButtonconvertionXCUBE, ButtonconvertionXCUBE_R, ButtonconvertionTradfriRemote, ButtonconvertionTradfriSwitch, ButtonconvertionGeneric, VibrationSensorConvertion
  60.  
  61. #from requests import async
  62.  
  63. #Better to use 'localhost' ?
  64. DOMOTICZ_IP = '127.0.0.1'
  65.  
  66. LIGHTLOG = True #To disable some activation, log will be lighter, but less informations.
  67. SETTODEFAULT = False #To set device in default state after a rejoin
  68.  
  69. #https://github.com/febalci/DomoticzEarthquake/blob/master/plugin.py
  70. #https://stackoverflow.com/questions/32436864/raw-post-request-with-json-in-body
  71.  
  72. class BasePlugin:
  73.  
  74.     #enabled = False
  75.  
  76.     def __init__(self):
  77.         self.Devices = {} # id, type, state (banned/missing/working) , model
  78.         self.NeedToReset = []
  79.         self.Ready = False
  80.         self.Buffer_Command = []
  81.         self.Buffer_Time = ''
  82.         self.WebSocket = None
  83.         self.WebsoketBuffer = ''
  84.         self.Banned_Devices = []
  85.         self.BufferReceive = ''
  86.         self.BufferLenght = 0
  87.  
  88.         self.INIT_STEP = ['config','lights','sensors','groups']
  89.  
  90.         return
  91.  
  92.     def onStart(self):
  93.         Domoticz.Debug("onStart called")
  94.         #CreateDevice('1111','sensors','On/Off light')
  95.  
  96.         #Check Domoticz IP
  97.         if Parameters["Address"] != '127.0.0.1' and Parameters["Address"] != 'localhost':
  98.             global DOMOTICZ_IP
  99.             DOMOTICZ_IP = get_ip()
  100.             Domoticz.Log("Your haven't use 127.0.0.1 as IP, so I suppose deCONZ and Domoticz aren't on same machine")
  101.             Domoticz.Log("Taking " + DOMOTICZ_IP + " as Domoticz IP")
  102.  
  103.             if DOMOTICZ_IP == Parameters["Address"]:
  104.                 Domoticz.Status("Your have same IP for deCONZ and Domoticz why don't use 127.0.0.1 as IP")
  105.         else:
  106.             Domoticz.Log("Domoticz and deCONZ are on same machine")
  107.  
  108.         if Parameters["Mode3"] != "0":
  109.             Domoticz.Debugging(int(Parameters["Mode3"]))
  110.             #DumpConfigToLog()
  111.  
  112.         #Read banned devices
  113.         with open(Parameters["HomeFolder"]+"banned_devices.txt", 'r') as myPluginConfFile:
  114.             for line in myPluginConfFile:
  115.                 if not line.startswith('#'):
  116.                     self.Banned_Devices.append(line.strip())
  117.         myPluginConfFile.close()
  118.  
  119.         #Read and Set config
  120.         #json = '{"websocketnotifyall":true}'
  121.         #url = '/api/' + Parameters["Mode2"] + '/config/'
  122.         #self.SendCommand(url,json)
  123.  
  124.         # Disabled, not working for selector ...
  125.         #check for new icons
  126.         #if 'bulbs_group' not in Images:
  127.         #    try:
  128.         #        Domoticz.Image('icons/bulbs_group.zip').Create()
  129.         #    except:
  130.         #        Domoticz.Error("Can't create new icons")
  131.  
  132.     def onStop(self):
  133.         Domoticz.Debug("onStop called")
  134.         if self.WebSocket:
  135.             self.WebSocket.Disconnect()
  136.  
  137.     def onConnect(self, Connection, Status, Description):
  138.         Domoticz.Debug("onConnect called")
  139.  
  140.         if Connection.Name == 'deCONZ_WebSocket':
  141.  
  142.             if (Status != 0):
  143.                 Domoticz.Error("WebSocket connexion error : " + str(Connection))
  144.                 Domoticz.Error("Status : " + str(Status) + " Description : " + str(Description) )
  145.                 return
  146.  
  147.             Domoticz.Status("Launching websocket on port " + str(Connection.Port) )
  148.             #Need to Add Sec-Websocket-Protocol : domoticz ????
  149.             #Boring error > Socket Shutdown Error: 9, Bad file descriptor
  150.             wsHeader = "GET / HTTP/1.1\r\n" \
  151.                         "Host: "+ Parameters["Address"] + ':' + str(Connection.Port) + "\r\n" \
  152.                         "User-Agent: Domoticz/1.0\r\n" \
  153.                         "Sec-WebSocket-Version: 13\r\n" \
  154.                         "Origin: http://" + DOMOTICZ_IP + "\r\n" \
  155.                         "Sec-WebSocket-Key: qqMLBxyyjz9Tog1bll7K6A==\r\n" \
  156.                         "Connection: keep-alive, Upgrade\r\n" \
  157.                         "Upgrade: websocket\r\n\r\n"
  158.                         #"Accept: Content-Type: text/html; charset=UTF-8\r\n" \
  159.                         #"Pragma: no-cache\r\n" \
  160.                         #"Cache-Control: no-cache\r\n" \
  161.                         #"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" \
  162.             self.WebSocket.Send(wsHeader)
  163.  
  164.         else:
  165.             Domoticz.Error("Unknow connexion : " + str(Connection))
  166.             Domoticz.Error("Status : " + str(Status) + " Description : " + str(Description) )
  167.             return
  168.  
  169.     def onMessage(self, Connection, Data):
  170.         Domoticz.Debug("onMessage called")
  171.  
  172.         _Data = []
  173.  
  174.         if self.WebsoketBuffer:
  175.             Data = self.WebsoketBuffer + Data
  176.             self.WebsoketBuffer = ''
  177.  
  178.         #Domoticz.Log("Data : " + str(Data))
  179.         #Domoticz.Log("Connexion : " + str(Connection))
  180.         #Domoticz.Log("Byte needed : " + str(Connection.BytesTransferred()) +  "ATM : " + str(len(Data)))
  181.         #The max is 4096 so if the data size excess 4096 byte it will be cut
  182.  
  183.         #Websocket data ?
  184.         if (Connection.Name == 'deCONZ_WebSocket'):
  185.             #Data = b'\x81W{"e":"changed","id":"7","r":"groups","state":{"all_on":true,"any_on":true}}'
  186.             #Data = b'\x81W{"e":"changed","id":"5","r":"groups","state":{"all_on":true,"any_on"'
  187.  
  188.             if Data.startswith(b'\x81'):
  189.                 while len(Data) > 0:
  190.                     try:
  191.                         payload, extra_data = get_JSON_payload(Data)
  192.                     except:
  193.                         if (Data[0:1] == b'\x81') and (len(str(Data)) < 300) :
  194.                             self.WebsoketBuffer = Data
  195.                             Domoticz.Log("Incomplete Json keep it for later : " + str(self.WebsoketBuffer) )
  196.                         else:
  197.                             Domoticz.Error("Malformed JSON response, can't repair : " + str(Data) )
  198.                         break
  199.                     _Data.append(payload)
  200.                     Data = extra_data
  201.  
  202.                 for js in _Data:
  203.                     self.WebSocketConnexion(js)
  204.             else:
  205.                 Domoticz.Log("Websocket Handshake : " + str(Data.decode("utf-8", "ignore").replace('\n','***')) )
  206.  
  207.         else:
  208.             Domoticz.Log("Unknow Connection" + str(Connection))
  209.             Domoticz.Log("Data : " + str(Data))
  210.             return
  211.  
  212.     def onCommand(self, Unit, Command, Level, Hue):
  213.         Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level) + ", Hue: " + str(Hue))
  214.  
  215.         if not self.Ready == True:
  216.             Domoticz.Error("deCONZ not ready")
  217.             return
  218.  
  219.         _type,deCONZ_ID = self.GetDevicedeCONZ(Devices[Unit].DeviceID)
  220.  
  221.         if not deCONZ_ID:
  222.             Domoticz.Error("Device not ready : " + str(Unit) )
  223.             return
  224.  
  225.         if _type == 'sensors':
  226.             Domoticz.Error("This device don't support action")
  227.             return
  228.  
  229.         _json = {}
  230.  
  231.         #on/off
  232.         if Command == 'On':
  233.             _json['on'] = True
  234.             if Level:
  235.                 _json['bri'] = round(Level*254/100)
  236.         if Command == 'Off':
  237.             _json['on'] = False
  238.  
  239.         #level
  240.         if Command == 'Set Level':
  241.             #To prevent bug
  242.             _json['on'] = True
  243.  
  244.             _json['bri'] = round(Level*254/100)
  245.  
  246.             #thermostat situation
  247.             if _type == 'config':
  248.                 _json.clear()
  249.                 _json['mode'] = "auto"
  250.                 _json['heatsetpoint'] = Level
  251.  
  252.         #color
  253.         if Command == 'Set Color':
  254.  
  255.             #To prevent bug
  256.             _json['on'] = True
  257.  
  258.             Hue_List = json.loads(Hue)
  259.  
  260.             #ColorModeNone = 0   // Illegal
  261.             #ColorModeNone = 1   // White. Valid fields: none
  262.             if Hue_List['m'] == 1:
  263.                 ww = int(Hue_List['ww']) # Can be used as level for monochrome white
  264.                 #TODO : Jamais vu un device avec ca encore
  265.                 Domoticz.Debug("Not implemented device color 1")
  266.             #ColorModeTemp = 2   // White with color temperature. Valid fields: t
  267.             if Hue_List['m'] == 2:
  268.                 #Value is in mireds (not kelvin)
  269.                 #Correct values are from 153 (6500K) up to 588 (1700K)
  270.                 # t is 0 > 255
  271.                 TempKelvin = int(((255 - int(Hue_List['t']))*(6500-1700)/255)+1700);
  272.                 TempMired = 1000000 // TempKelvin
  273.                 #if previous not working
  274.                 #TempMired = round(float(Hue_List['t'])*(500.0f - 153.0f) / 255.0f + 153.0f)
  275.                 _json['ct'] = TempMired
  276.             #ColorModeRGB = 3    // Color. Valid fields: r, g, b.
  277.             elif Hue_List['m'] == 3:
  278.                 IEEE = Devices[Unit].DeviceID
  279.                 if self.Devices[IEEE].get('colormode','Unknow') == 'hs':
  280.                     h,l,s = rgb_to_hsl((int(Hue_List['r']),int(Hue_List['g']),int(Hue_List['b'])))
  281.                     hue = int(h * 65535)
  282.                     saturation = int(s * 254)
  283.                     value = int(l * 254/100)
  284.                     _json['hue'] = hue
  285.                     _json['sat'] = saturation
  286.                     _json['bri'] = value
  287.                     _json['transitiontime'] = 0
  288.                 else:
  289.                     x, y = rgb_to_xy((int(Hue_List['r']),int(Hue_List['g']),int(Hue_List['b'])))
  290.                     x = round(x,6)
  291.                     y = round(y,6)
  292.                     _json['xy'] = [x,y]
  293.             #ColorModeCustom = 4, // Custom (color + white). Valid fields: r, g, b, cw, ww, depending on device capabilities
  294.             elif Hue_List['m'] == 4:
  295.                 ww = int(Hue_List['ww'])
  296.                 cw = int(Hue_List['cw'])
  297.                 x, y = rgb_to_xy((int(Hue_List['r']),int(Hue_List['g']),int(Hue_List['b'])))
  298.                 #TODO, Pas trouve de device avec ca encore ...
  299.                 Domoticz.Debug("Not implemented device color 2")
  300.  
  301.             #To prevent bug
  302.             if '"bri":' not in _json:
  303.                 _json['bri'] = round(Level*254/100)
  304.                 _json['transitiontime'] = 0
  305.  
  306.  
  307.         url = '/api/' + Parameters["Mode2"] + '/' + _type + '/' + str(deCONZ_ID)
  308.         if _type == 'lights':
  309.             url = url + '/state'
  310.         elif _type == 'config':
  311.             url = '/api/' + Parameters["Mode2"] + '/sensors/' + str(deCONZ_ID) + '/config'
  312.         elif _type == 'scenes':
  313.             url = '/api/' + Parameters["Mode2"] + '/groups/' + deCONZ_ID.split('/')[0] + '/scenes/' + deCONZ_ID.split('/')[1] + '/recall'
  314.             _json = {} # to force PUT
  315.         else:
  316.             url = url + '/action'
  317.  
  318.         self.SendCommand(url,_json)
  319.  
  320.     def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile):
  321.         Domoticz.Log("Notification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile)
  322.  
  323.     def onDisconnect(self, Connection):
  324.         Domoticz.Status("onDisconnect called for " + str(Connection.Name) )
  325.  
  326.     def onHeartbeat(self):
  327.         Domoticz.Debug("onHeartbeat called")
  328.  
  329.         #Check for freeze
  330.         if len(self.Buffer_Command) > 0:
  331.             self.UpdateBuffer()
  332.  
  333.         #Initialisation
  334.         if self.Ready != True:
  335.             if len(self.INIT_STEP) > 0:
  336.                 Domoticz.Debug("### Initialisation > " + str(self.INIT_STEP[0]))
  337.                 self.ManageInit()
  338.  
  339.                 #Stop all here
  340.                 return
  341.             else:
  342.                self.Ready = True
  343.  
  344.         #Check websocket connexion
  345.         if self.WebSocket:
  346.             if not self.WebSocket.Connected():
  347.                 Domoticz.Error("WebSocket Disconnected, reconnexion !")
  348.                 self.WebSocket.Connect()
  349.  
  350.         #reset switchs
  351.         if len(self.NeedToReset) > 0 :
  352.             for IEEE in self.NeedToReset:
  353.                 _id = False
  354.                 for i in self.Devices:
  355.                     if i == IEEE:
  356.                         _id = self.Devices[i]['id']
  357.                 UpdateDevice(_id,'sensors', { 'nValue' : 0 , 'sValue' : 'Off' } )
  358.             self.NeedToReset = []
  359.  
  360.         #Devices[27].Update(nValue=0, sValue='11;22' )
  361.  
  362.     def onDeviceRemoved(self,unit):
  363.         Domoticz.Log("Device Removed")
  364.         #TODO : Need to rescan all
  365.  
  366. #---------------------------------------------------------------------------------------
  367.  
  368.     def ManageInit(self,pop = False):
  369.  
  370.         if pop:
  371.             self.INIT_STEP.pop(0)
  372.         if len(self.INIT_STEP) < 1:
  373.             self.Ready = True
  374.  
  375.             Domoticz.Status("### deCONZ ready")
  376.             l,s,g,b,o,c = Count_Type(self.Devices)
  377.             Domoticz.Status("### Found " + str(l) + " Operators, " + str(s) + " Sensors, " + str(g) + " Groups, " + str(c) + " Scenes and " + str(o) + " others, with " + str(b) + " Ignored")
  378.  
  379.             # Compare devices bases
  380.             for i in Devices:
  381.                 if Devices[i].DeviceID not in self.Devices:
  382.                     Domoticz.Status('### Device ' + Devices[i].DeviceID + '(' + Devices[i].Name + ') Not in deCONZ ATM, the device is deleted or not ready.')
  383.  
  384.             return
  385.  
  386.         #No flood during initialisation
  387.         if len(self.Buffer_Command) > 0:
  388.             u,d = self.Buffer_Command[-1]
  389.             if "/" + self.INIT_STEP[0] + "/" in u:
  390.                 Domoticz.Log("### Still waiting")
  391.                 return
  392.  
  393.         Domoticz.Log("### Request " + self.INIT_STEP[0])
  394.         self.SendCommand("/api/" + Parameters["Mode2"] + "/" + self.INIT_STEP[0] + "/")
  395.  
  396.     def InitDomoticzDB(self,key,_Data,Type_device):
  397.  
  398.         return
  399.         #Lights or sensors ?
  400.         if 'uniqueid' in _Data:
  401.  
  402.             IEEE = str(_Data['uniqueid'])
  403.             Name = str(_Data['name'])
  404.             Type = str(_Data['type'])
  405.             Model = str(_Data.get('modelid',''))
  406.             if not Model:
  407.                 Model = ''
  408.  
  409.             #Type_device = 'lights'
  410.             #if not 'hascolor' in _Data[i]:
  411.             #    Type_device = 'sensors'
  412.  
  413.             Domoticz.Log("### Device > " + str(key) + ' Name:' + Name + ' Type:' + Type + ' Details:' + str(_Data['state']))
  414.  
  415.             self.Devices[IEEE] = {'id' : key , 'type' : Type_device , 'model' : Type , 'state' : 'working'}
  416.  
  417.             #Skip banned device
  418.             if IEEE in self.Banned_Devices:
  419.                 Domoticz.Log("Skipping Device (Banned) : " + str(IEEE) )
  420.                 self.Devices[IEEE]['state'] = 'banned'
  421.                 return
  422.  
  423.             #Get some infos
  424.             kwarg = {}
  425.             if 'state' in _Data:
  426.                 state = _Data['state']
  427.                 kwarg.update(ProcessAllState(state,Model))
  428.                 if 'colormode' in state:
  429.                     self.Devices[IEEE]['colormode'] = state['colormode']
  430.  
  431.             if 'config' in _Data:
  432.                 config = _Data['config']
  433.                 kwarg.update(ProcessAllConfig(config))
  434.  
  435.             #It's a switch ? Need special process
  436.             if Type == 'ZHASwitch' or Type == 'ZGPSwitch' or Type == 'CLIPSwitch':
  437.  
  438.                 #Set it to off
  439.                 kwarg.update({'sValue': 'Off', 'nValue': 0})
  440.  
  441.                 #ignore ZHASwitch if vibration sensor
  442.                 if 'sensitivity' in _Data['config']:
  443.                     return
  444.  
  445.                 if 'lumi.sensor_cube' in Model:
  446.                     if IEEE.endswith('-03-000c'):
  447.                         Type = 'XCube_R'
  448.                     elif IEEE.endswith('-02-0012'):
  449.                         Type = 'XCube_C'
  450.                     else:
  451.                         # Useless device
  452.                         self.Devices[IEEE]['state'] = 'banned'
  453.                         return
  454.                 elif 'TRADFRI remote control' in Model:
  455.                     Type = 'Tradfri_remote'
  456.                 #elif 'RWL021' in Model:
  457.                 #    Type = 'Tradfri_remote'
  458.                 elif 'TRADFRI on/off switch' in Model:
  459.                     Type = 'Tradfri_on/off_switch'
  460.                 else:
  461.                     Type = 'Switch_Generic'
  462.  
  463.                 self.Devices[IEEE]['model'] = Type
  464.  
  465.             if self.Ready == True:
  466.                 Domoticz.Status("Adding missing device :" + str(key) + ' Type:' + str(Type))
  467.  
  468.             #Not exist > create
  469.             if GetDomoDeviceInfo(IEEE) == False:
  470.                 #Special devices
  471.                 if Type == 'ZHAThermostat':
  472.                     #Create a setpoint device
  473.                     self.Devices[IEEE + "_heatsetpoint"] = {'id' : key , 'type' : 'config' , 'state' : 'working' , 'model' : 'ZHAThermostat' }
  474.                     CreateDevice(IEEE + "_heatsetpoint" ,Name,'ZHAThermostat')
  475.                     #Transform the current device in tmeperature device
  476.                     Type = 'ZHATemperature'
  477.  
  478.                 CreateDevice(IEEE,Name,Type)
  479.  
  480.             #update
  481.             if kwarg:
  482.                 UpdateDevice(key,Type_device,kwarg)
  483.  
  484.         #groups
  485.         else:
  486.  
  487.             Name = str(_Data['name'])
  488.             Type = str(_Data['type'])
  489.             Domoticz.Log("### Groupe > " + str(key) + ' Name:' + Name )
  490.             Dev_name = 'GROUP_' + Name.replace(' ','_')
  491.             self.Devices[Dev_name] = {'id' : key , 'type' : 'groups' , 'model' : 'groups', 'state' : 'working'}
  492.  
  493.             # Skip banned group
  494.             if Dev_name in self.Banned_Devices:
  495.                 Domoticz.Log("Skipping Group (Banned) : " + str(Dev_name) )
  496.                 self.Devices[Dev_name]['state'] = 'banned'
  497.  
  498.             else:
  499.                 #Check for scene
  500.                 scenes = _Data.get('scenes',[])
  501.                 if len(scenes) > 0:
  502.                     for j in scenes:
  503.                         Domoticz.Log("### Scenes associated with group " + str(key) + " > ID:" + str(j['id']) + " Name:" + str(j['name']) )
  504.                         Scene_name = 'SCENE_' + str(j['name']).replace(' ','_')
  505.                         self.Devices[Scene_name] = {'id' : str(key) + '/' + str(j['id']) , 'type' : 'scenes' , 'model' : 'scenes'}
  506.                         #^scene not exist > create
  507.                         if GetDomoDeviceInfo(Scene_name) == False:
  508.                             CreateDevice(Scene_name,str(j['name']),'Scenes')
  509.  
  510.                 #Group not exist > create
  511.                 if GetDomoDeviceInfo(Dev_name) == False:
  512.                     CreateDevice(Dev_name,Name,Type)
  513.  
  514.  
  515.     def NormalConnexion(self,_Data):
  516.  
  517.         Domoticz.Debug("Classic Data : " + str(_Data) )
  518.  
  519.         #JSON with data returned >> _Data = [{'success': {'/lights/2/state/on': True}}, {'success': {'/lights/2/state/bri': 251}}]
  520.         if isinstance(_Data, list):
  521.             self.ReadReturn(_Data)
  522.         else:
  523.             if (self.Ready != True):
  524.                 #JSON with config
  525.                 if 'bridgeid' in _Data:
  526.                     if 'websocketnotifyall' in _Data:
  527.                         self.ReadConfig(_Data)
  528.                     else:
  529.                         Domoticz.Error("Bad API KEY !")
  530.                 else:
  531.                     #JSON with device info like {'1': {'data:1}}
  532.                     for i in _Data:
  533.                         self.InitDomoticzDB(i,_Data[i],self.INIT_STEP[0])
  534.  
  535.                     #Update initialisation
  536.                     self.ManageInit(True)
  537.             else:
  538.                 #JSON with device info like {'data:1}
  539.                 typ,_id = self.GetDevicedeCONZ(_Data.get('uniqueid','') )
  540.                 if _id:
  541.                     self.InitDomoticzDB(_id,_Data,typ)
  542.                 #Check for groups
  543.                 else:
  544.                     _id = _Data.get('id','')
  545.                     if _id:
  546.                         self.InitDomoticzDB(_id,_Data,'groups')
  547.  
  548.     def ReadReturn(self,_Data):
  549.         kwarg = {}
  550.         _id = False
  551.         _type = False
  552.  
  553.         for _Data2 in _Data:
  554.  
  555.             First_item = next(iter(_Data2))
  556.  
  557.             #Command Error
  558.             if First_item == 'error':
  559.                 Domoticz.Error("deCONZ error :" + str(_Data2))
  560.                 if _Data2['error']['type'] == 3:
  561.                     dev = _Data2['error']['address'].split('/')
  562.                     _id = dev[2]
  563.                     _type = dev[1]
  564.                     #Set red header
  565.                     kwarg.update({'TimedOut':1})
  566.  
  567.             #Command sucess
  568.             elif First_item == 'success':
  569.  
  570.                 data = _Data2['success']
  571.                 dev = (list(data.keys())[0] ).split('/')
  572.                 val = data[list(data.keys())[0]]
  573.  
  574.                 if len(dev) < 3:
  575.                     pass
  576.                 else:
  577.                     if not _id:
  578.                         _id = dev[2]
  579.                         _type = dev[1]
  580.  
  581.                     if dev[1] == 'config':
  582.                         Domoticz.Status("Editing configuration : " + str(data) )
  583.  
  584.             else:
  585.                 Domoticz.Error("Not managed return JSON : " + str(_Data2) )
  586.  
  587.         if kwarg:
  588.             UpdateDevice(_id,_type,kwarg)
  589.  
  590.     def ReadConfig(self,_Data):
  591.         #trick to test is deconz is ready
  592.         fw = _Data['fwversion']
  593.         if fw == '0x00000000':
  594.             Domoticz.Error("Wrong startup, retrying !!")
  595.             #Cancel this part to restart it after 1 heartbeat (10s)
  596.             return
  597.         Domoticz.Status("Firmware version : " + _Data['fwversion'] )
  598.         Domoticz.Status("Websocketnotifyall : " + str(_Data['websocketnotifyall']))
  599.         if not _Data['websocketnotifyall'] == True:
  600.             Domoticz.Error("Websocketnotifyall is not set to True")
  601.  
  602.         #Launch Web socket connexion
  603.         self.WebSocket = Domoticz.Connection(Name="deCONZ_WebSocket", Transport="TCP/IP", Address=Parameters["Address"], Port=str(_Data['websocketport']) )
  604.         self.WebSocket.Connect()
  605.  
  606.         self.ManageInit(True)
  607.  
  608.     def WebSocketConnexion(self,_Data):
  609.  
  610.         Domoticz.Debug("### WebSocket Data : " + str(_Data) )
  611.  
  612.         if not self.Ready == True:
  613.             Domoticz.Error("deCONZ not ready")
  614.             return
  615.  
  616.         if 'e' in _Data:
  617.             if _Data['e'] == 'deleted':
  618.                 return
  619.             if _Data['e'] == 'added':
  620.                 return
  621.             if _Data['e'] == 'scene-called':
  622.                 Domoticz.Log("Playing scene > group:" + str(_Data['gid']) + " Scene:" + str(_Data['scid']) )
  623.                 return
  624.  
  625.         #Take care, no uniqueid for groups
  626.         IEEE,state = self.GetDeviceIEEE(_Data['id'],_Data['r'])
  627.  
  628.         #Patch for device with double UniqueID
  629.         if (not IEEE) and ('uniqueid' in _Data):
  630.             typ,_id = self.GetDevicedeCONZ(_Data['uniqueid'] )
  631.             if _id:
  632.                 Domoticz.Log("Double UniqueID correction : " + _Data['id'] + ' > ' + str(_id) )
  633.                 _Data['id'] = _id
  634.                 IEEE,state = self.GetDeviceIEEE(_Data['id'],_Data['r'])
  635.  
  636.         if not IEEE:
  637.             if 'uniqueid' in _Data:
  638.  
  639.                 Domoticz.Error("Websocket error, unknow device > " + str(_Data['id']) + ' (' + str(_Data['r']) + ') Asking for information')
  640.                 IEEE = str(_Data['uniqueid'])
  641.                 #Try getting informations
  642.                 self.Devices[IEEE] = {'id' : str(_Data['id']) , 'type' : str(_Data['r']) , 'state' : 'missing'}
  643.                 self.SendCommand('/api/' + Parameters["Mode2"] + '/' + str(_Data['r']) + '/' + str(_Data['id']) )
  644.             else:
  645.                 Domoticz.Error("Websocket error, unknow device > " + str(_Data['id']) + ' (' + str(_Data['r']) + ')')
  646.                 #Try getting informations
  647.                 if str(_Data['r']) == 'groups':
  648.                     #Name = str(_Data['name'])
  649.                     #Dev_name = 'GROUP_' + Name.replace(' ','_')
  650.                     #self.Devices[Dev_name] = {'id' : str(_Data['id']) , 'type' : 'groups' , 'model' : 'groups', 'state' : 'missing'}
  651.                     self.SendCommand('/api/' + Parameters["Mode2"] + '/groups/' + str(_Data['id']) )
  652.  
  653.             return
  654.         if state == 'banned':
  655.             Domoticz.Debug("Banned device > " + str(_Data['id']) + ' (' + str(_Data['r']) + ')')
  656.             return
  657.         if state == 'missing':
  658.             Domoticz.Error("Missing device > " + str(_Data['id']) + ' (' + str(_Data['r']) + ')')
  659.             return
  660.  
  661.         model = self.Devices[IEEE].get('model','')
  662.  
  663.         kwarg = {}
  664.  
  665.         #MAJ State : _Data['e'] == 'changed'
  666.         if 'state' in _Data:
  667.             state = _Data['state']
  668.             kwarg.update(ProcessAllState(state , model))
  669.  
  670.             if 'buttonevent' in state:
  671.                 if model == 'XCube_C':
  672.                     kwarg.update(ButtonconvertionXCUBE( state['buttonevent'] ) )
  673.                 elif model == 'XCube_R':
  674.                     kwarg.update(ButtonconvertionXCUBE_R( state['buttonevent'] ) )
  675.                 elif model == 'Tradfri_remote':
  676.                     kwarg.update(ButtonconvertionTradfriRemote( state['buttonevent'] ) )
  677.                 elif model == 'Tradfri_on/off_switch':
  678.                     kwarg.update(ButtonconvertionTradfriSwitch( state['buttonevent'] ) )
  679.                 else:
  680.                     kwarg.update(ButtonconvertionGeneric( state['buttonevent'] ) )
  681.                 if IEEE not in self.NeedToReset:
  682.                     self.NeedToReset.append(IEEE)
  683.  
  684.             if 'vibration' in state:
  685.                 kwarg.update(VibrationSensorConvertion( state['vibration'] , state.get('tiltangle',None)) )
  686.  
  687.             if 'reachable' in state:
  688.                 if state['reachable'] == True:
  689.                     Unit = GetDomoDeviceInfo(IEEE)
  690.                     #Jump following action if Unit content is not valid
  691.                     if Unit != False:
  692.                         LUpdate = Devices[Unit].LastUpdate
  693.                         LUpdate=time.mktime(time.strptime(LUpdate,"%Y-%m-%d %H:%M:%S"))
  694.                         current = time.time()
  695.  
  696.                         if (SETTODEFAULT):
  697.                             #Check if the device has been see, at least 10 s ago
  698.                             if (current-LUpdate) > 10:
  699.                                 Domoticz.Status("###### Device just re-connected : " + str(_Data) + "Set to defaut state")
  700.                                 self.SetDeviceDefautState(IEEE,_Data['r'])
  701.                             else:
  702.                                 Domoticz.Status("###### Device just re-connected : " + str(_Data) + "But ignored")
  703.  
  704.             if ('tampered' in state) or ('lowbattery' in state):
  705.                 tampered = state.get('tampered',False)
  706.                 lowbattery = state.get('lowbattery',False)
  707.                 if tampered or lowbattery:
  708.                     kwarg.update({'TimedOut':1})
  709.                     Domoticz.Error("###### Device with hardware defaut : " + str(_Data))
  710.  
  711.  
  712.         #MAJ config
  713.         elif 'config' in _Data:
  714.             config = _Data['config']
  715.             kwarg.update(ProcessAllConfig(config))
  716.  
  717.         else:
  718.             Domoticz.Error("Unknow MAJ" + str(_Data) )
  719.  
  720.         if kwarg:
  721.             UpdateDevice(_Data['id'],_Data['r'],kwarg)
  722.  
  723.     def DeleteDeviceFromdeCONZ(self,_id):
  724.  
  725.         url = '/api/' + Parameters["Mode2"] + '/sensors/' + str(_id)
  726.  
  727.         self.Buffer_Command.append((url,'delete'))
  728.         self.UpdateBuffer()
  729.  
  730.         Domoticz.Status("### Deleting device " + str(_id))
  731.  
  732.     def SendCommand(self,url,data=None):
  733.  
  734.         Domoticz.Debug("Send Command " + url + " with " + str(data) + ' (' + str(len(self.Buffer_Command)) + ' in buffer)')
  735.  
  736.         sendData = (url , data)
  737.         self.Buffer_Command.append(sendData)
  738.         self.UpdateBuffer()
  739.  
  740.     def GetDevicedeCONZ(self,IEEE):
  741.         if IEEE in self.Devices:
  742.             return self.Devices[IEEE]['type'],self.Devices[IEEE]['id']
  743.  
  744.         return False,False
  745.  
  746.     def UpdateBuffer(self):
  747.         if len(self.Buffer_Command) == 0:
  748.             return
  749.  
  750.         debut_time = time.time()
  751.  
  752.         while len(self.Buffer_Command) > 0:
  753.  
  754.             u , c = self.Buffer_Command.pop(0)
  755.  
  756.             _Data = MakeRequest('http://' + Parameters["Address"] + ':' + Parameters["Port"] + str(u) , c)
  757.  
  758.             #If not data usefull
  759.             if len(_Data) == 0:
  760.                 return
  761.  
  762.             #Clean data
  763.             #_Data = _Data.replace('true','True').replace('false','False').replace('null','None').replace('\n','***').replace('\00','')
  764.             try:
  765.                 _Data = json.loads(_Data)
  766.             except:
  767.                 #Sometime the connexion bug, trying to repair
  768.                 Domoticz.Error("Malformed JSON response, Trying to repair : " + str(_Data) )
  769.                 _Data = JSON_Repair(_Data)
  770.                 try:
  771.                     _Data = json.loads(_Data)
  772.                     Domoticz.Error("New Data repaired : " + str(_Data))
  773.                 except:
  774.                     Domoticz.Error("Can't repair malformed JSON: " + str(_Data) )
  775.                     _Data = None
  776.  
  777.             #traitement
  778.             if not _Data == None: #WARNING None because can be {}
  779.                 self.NormalConnexion(_Data)
  780.  
  781.             fin_time = time.time()
  782.  
  783.             # if the process take more than 1s, skip all, not normal
  784.             if fin_time - debut_time > 1 :
  785.                 Domoticz.Error("Process request take too much time : " + str(fin_time - debut_time) + ' s')
  786.                 break
  787.  
  788.         return
  789.  
  790.     def GetDeviceIEEE(self,_id,_type):
  791.         for IEEE in self.Devices:
  792.             if (self.Devices[IEEE]['type'] == _type) and (self.Devices[IEEE]['id'] == _id):
  793.                 return IEEE,self.Devices[IEEE].get('state','unknow')
  794.  
  795.         return False,'unknow'
  796.  
  797.     def SetDeviceDefautState(self,IEEE,_type):
  798.         # Set bulb on same state than in domoticz
  799.         if _type == 'lights':
  800.             Unit = GetDomoDeviceInfo(IEEE)
  801.             if Devices[Unit].nValue == 0:
  802.                 _json = '{"on":false}'
  803.             else:
  804.                 _json = '{"on":true}'
  805.             dummy,deCONZ_ID = self.GetDevicedeCONZ(IEEE)
  806.             url = '/api/' + Parameters["Mode2"] + '/lights/' + str(deCONZ_ID) + '/state'
  807.             self.SendCommand(url,_json)
  808.  
  809. global _plugin
  810. _plugin = BasePlugin()
  811.  
  812. def onStart():
  813.     global _plugin
  814.     _plugin.onStart()
  815.  
  816. def onStop():
  817.     global _plugin
  818.     _plugin.onStop()
  819.  
  820. def onConnect(Connection, Status, Description):
  821.     global _plugin
  822.     _plugin.onConnect(Connection, Status, Description)
  823.  
  824. def onMessage(Connection, Data):
  825.     global _plugin
  826.     _plugin.onMessage(Connection, Data)
  827.  
  828. def onCommand(Unit, Command, Level, Hue):
  829.     global _plugin
  830.     _plugin.onCommand(Unit, Command, Level, Hue)
  831.  
  832. def onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile):
  833.     global _plugin
  834.     _plugin.onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile)
  835.  
  836. def onDisconnect(Connection):
  837.     global _plugin
  838.     _plugin.onDisconnect(Connection)
  839.  
  840. def onHeartbeat():
  841.     global _plugin
  842.     _plugin.onHeartbeat()
  843.  
  844. def onDeviceRemoved(unit):
  845.     global _plugin
  846.     _plugin.onDeviceRemoved(unit)
  847.  
  848.     # Generic helper functions
  849. def DumpConfigToLog():
  850.     for x in Parameters:
  851.         if Parameters[x] != "":
  852.             Domoticz.Debug( "'" + x + "':'" + str(Parameters[x]) + "'")
  853.     Domoticz.Debug("Device count: " + str(len(Devices)))
  854.     for x in Devices:
  855.         Domoticz.Debug("Device:           " + str(x) + " - " + str(Devices[x]))
  856.         Domoticz.Debug("Device ID:       '" + str(Devices[x].ID) + "'")
  857.         Domoticz.Debug("Device Name:     '" + Devices[x].Name + "'")
  858.         Domoticz.Debug("Device nValue:    " + str(Devices[x].nValue))
  859.         Domoticz.Debug("Device sValue:   '" + Devices[x].sValue + "'")
  860.         Domoticz.Debug("Device LastLevel: " + str(Devices[x].LastLevel))
  861.     return
  862.  
  863. def GetDeviceIEEE(id,type):
  864.     global _plugin
  865.     return _plugin.GetDeviceIEEE(id,type)
  866.  
  867. #*****************************************************************************************************
  868.  
  869. def MakeRequest(url,param=None):
  870.  
  871.     Domoticz.Debug("Making Request : " + url  + ' with params ' + str(param) )
  872.  
  873.     data = ''
  874.  
  875.     try:
  876.         if not param == None:
  877.             if param == 'delete':
  878.                 result=requests.delete(url, headers={'Content-Type': 'application/json' }, timeout=1)
  879.             else:
  880.                 headers={'Content-Type': 'application/json' }
  881.                 result=requests.put(url , headers=headers, json = param, timeout=1)
  882.         else :
  883.             result=requests.get(url, headers={'Content-Type': 'application/json' }, timeout=1)
  884.  
  885.         if result.status_code  == 200 :
  886.             data = result.content
  887.         else:
  888.             Domoticz.Error( "Connexion problem (1) with Gateway : " + str(result.status_code) )
  889.             return ''
  890.     except:
  891.         if not REQUESTPRESENT:
  892.             Domoticz.Error("Your pyton version miss requests library")
  893.             Domoticz.Error("To install it, type : sudo -H pip3 install requests | sudo -H pip install requests")
  894.         else:
  895.             try:
  896.                 Domoticz.Error( "Connexion problem (2) with Gateway : " + str(result.status_code) )
  897.             except:
  898.                 Domoticz.Error( "Connexion problem (3) with Gateway, check your API key")
  899.         return ''
  900.  
  901.     Domoticz.Debug('Request Return : ' + str(data.decode("utf-8", "ignore")) )
  902.  
  903.     return data.decode("utf-8", "ignore")
  904.  
  905. def get_ip():
  906.     import socket
  907.     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  908.     try:
  909.         # doesn't even have to be reachable
  910.         s.connect(('10.255.255.255', 1))
  911.         IP = s.getsockname()[0]
  912.     except:
  913.         IP = '127.0.0.1'
  914.     finally:
  915.         s.close()
  916.     return IP
  917.  
  918. def GetDomoDeviceInfo(IEEE):
  919.     for x in Devices:
  920.         if Devices[x].DeviceID == str(IEEE) :
  921.             return x
  922.     return False
  923.  
  924. def FreeUnit() :
  925.     FreeUnit = ""
  926.     for x in range(1,256):
  927.         if x not in Devices :
  928.             FreeUnit=x
  929.             return FreeUnit
  930.     if FreeUnit == "" :
  931.         FreeUnit=len(Devices)+1
  932.     return FreeUnit
  933.  
  934. def GetDomoUnit(_id,_type):
  935.     try:
  936.         IEEE,state = GetDeviceIEEE(_id,_type)
  937.  
  938.         if IEEE == False:
  939.             Domoticz.Log("Device not in base, need resynchronisation ? > " + str(_id) + ' (' + str(_type) + ')')
  940.             return False
  941.         elif state == 'banned':
  942.             Domoticz.Log("Banned device > " + str(_id) + ' (' + str(_type) + ')')
  943.             return False
  944.         elif state == 'missing':
  945.             Domoticz.Log("missing device > " + str(_id) + ' (' + str(_type) + ')')
  946.             return False
  947.  
  948.         return GetDomoDeviceInfo(IEEE)
  949.     except:
  950.         return False
  951.  
  952.     return False
  953.  
  954. def UpdateDevice(_id,_type,kwarg):
  955.  
  956.     Unit = GetDomoUnit(_id,_type)
  957.  
  958.     if not Unit or not kwarg:
  959.         Domoticz.Error("Can't Update Unit > " + str(_id) + ' (' + str(_type) + ')' )
  960.         return
  961.  
  962.     #Check for special device.
  963.     if 'heatsetpoint' in kwarg:
  964.         v = kwarg.pop('heatsetpoint')
  965.         IEEE,dummy = GetDeviceIEEE(_id,_type)
  966.         Unit = GetDomoDeviceInfo(IEEE + '_heatsetpoint')
  967.         kwarg['nValue'] = 0
  968.         kwarg['nValue'] = str(v)
  969.  
  970.     #Do we need to update the sensor ?
  971.     NeedUpdate = False
  972.  
  973.     for a in kwarg:
  974.         if kwarg[a] != getattr(Devices[Unit], a ):
  975.             NeedUpdate = True
  976.             break
  977.  
  978.     #Force update even there is no change, for exemple in case the user press a switch too fast, to not miss an event
  979.     # Only for switch > 'LevelNames' in Devices[Unit].Options
  980.     # Only sensors >  _type == 'sensors'
  981.     if (('nValue' in kwarg) or ('sValue' in kwarg)) and ( ('LevelNames' in Devices[Unit].Options) and (kwarg['nValue'] != 0) ):
  982.         NeedUpdate = True
  983.  
  984.     #Disabled because no update for battery or last seen for exemple
  985.     #No need to trigger in this situation
  986.     #if (kwarg['nValue'] == Devices[Unit].nValue) and (kwarg['nValue'] == Devices[Unit].nValue) and ('Color' not in kwarg):
  987.     #    kwarg['SuppressTriggers'] = True
  988.  
  989.     #Alaways update for Color Bulb
  990.     if 'Color' in kwarg:
  991.         NeedUpdate = True
  992.  
  993.     #force update, at least 1 every 24h
  994.     if not NeedUpdate:
  995.         LUpdate = Devices[Unit].LastUpdate
  996.         LUpdate=time.mktime(time.strptime(LUpdate,"%Y-%m-%d %H:%M:%S"))
  997.         current = time.time()
  998.         if (current-LUpdate) > 86400:
  999.             NeedUpdate = True
  1000.  
  1001.     #Theses value are needed for Domoticz
  1002.     if 'nValue' not in kwarg:
  1003.         kwarg['nValue'] = Devices[Unit].nValue
  1004.     if 'sValue' not in kwarg:
  1005.         kwarg['sValue'] = Devices[Unit].sValue
  1006.     if Devices[Unit].TimedOut != 0 and kwarg.get('TimedOut',0) == 0:
  1007.         NeedUpdate = True
  1008.         kwarg['TimedOut'] = 0
  1009.  
  1010.     if NeedUpdate or not LIGHTLOG:
  1011.         Domoticz.Debug("### Update  device ("+Devices[Unit].Name+") : " + str(kwarg))
  1012.         Devices[Unit].Update(**kwarg)
  1013.     else:
  1014.         Domoticz.Debug("### Update  device ("+Devices[Unit].Name+") : " + str(kwarg) + ", IGNORED , no changes !")
  1015.  
  1016. def CreateDevice(IEEE,_Name,_Type):
  1017.     kwarg = {}
  1018.     Unit = FreeUnit()
  1019.     TypeName = ''
  1020.  
  1021.     #Operator
  1022.     if _Type == 'Color light' or _Type == 'Color dimmable light':
  1023.         kwarg['Type'] = 241
  1024.         kwarg['Subtype'] = 2
  1025.         kwarg['Switchtype'] = 7
  1026.  
  1027.     elif _Type == 'Extended color light':
  1028.         kwarg['Type'] = 241
  1029.         kwarg['Subtype'] = 7
  1030.         kwarg['Switchtype'] = 7
  1031.  
  1032.     elif _Type == 'Color temperature light':
  1033.         kwarg['Type'] = 241
  1034.         kwarg['Subtype'] = 8
  1035.         kwarg['Switchtype'] = 7
  1036.  
  1037.     elif _Type == 'Dimmable light' or _Type == 'Dimmable plug-in unit' or _Type == 'Dimmer switch':
  1038.         kwarg['Type'] = 244
  1039.         kwarg['Subtype'] = 73
  1040.         kwarg['Switchtype'] = 7
  1041.  
  1042.     elif _Type == 'Smart plug' or _Type == 'On/Off plug-in unit':
  1043.         kwarg['Type'] = 244
  1044.         kwarg['Subtype'] = 73
  1045.         kwarg['Switchtype'] = 0
  1046.         kwarg['Image'] = 1
  1047.  
  1048.     elif _Type == 'On/Off light' or _Type == 'On/Off output' or _Type == 'On/Off light switch':
  1049.         kwarg['Type'] = 244
  1050.         kwarg['Subtype'] = 73
  1051.         kwarg['Switchtype'] = 0
  1052.  
  1053.     elif _Type == 'Window covering device':
  1054.         kwarg['Type'] = 244
  1055.         kwarg['Subtype'] = 73
  1056.         kwarg['Switchtype'] = 16
  1057.  
  1058.     elif _Type == 'Door Lock':
  1059.         kwarg['Type'] = 244
  1060.         kwarg['Subtype'] = 73
  1061.         kwarg['Switchtype'] = 0
  1062.  
  1063.     #elif _Type == 'Fan':
  1064.  
  1065.     #Sensors
  1066.     elif _Type == 'Daylight':
  1067.         kwarg['Type'] = 244
  1068.         kwarg['Subtype'] = 73
  1069.         kwarg['Switchtype'] = 9
  1070.  
  1071.     elif _Type == 'ZHATemperature' or _Type == 'CLIPTemperature':
  1072.         kwarg['TypeName'] = 'Temperature'
  1073.  
  1074.     elif _Type == 'ZHAHumidity' or _Type == 'CLIPHumidity':
  1075.         kwarg['TypeName'] = 'Humidity'
  1076.  
  1077.     elif _Type == 'ZHAPressure'or _Type == 'CLIPPressure':
  1078.         kwarg['TypeName'] = 'Barometer'
  1079.  
  1080.     elif _Type == 'ZHAOpenClose' or _Type == 'CLIPOpenClose':
  1081.         kwarg['Type'] = 244
  1082.         kwarg['Subtype'] = 73
  1083.         kwarg['Switchtype'] = 11
  1084.  
  1085.     elif _Type == 'ZHAPresence' or _Type == 'CLIPPresence':
  1086.         kwarg['Type'] = 244
  1087.         kwarg['Subtype'] = 73
  1088.         kwarg['Switchtype'] = 8
  1089.  
  1090.     elif _Type == 'ZHALightLevel' or _Type == 'CLIPLightLevel' or _Type == 'ZHALight':
  1091.         kwarg['TypeName'] = 'Illumination'
  1092.  
  1093.     elif _Type == 'ZHAConsumption':# in kWh
  1094.         kwarg['TypeName'] = 'kWh'
  1095.  
  1096.     elif _Type == 'ZHAPower':# in W
  1097.         kwarg['TypeName'] = 'Usage'
  1098.  
  1099.     elif _Type == 'ZHAVibration':
  1100.         kwarg['Type'] = 244
  1101.         kwarg['Subtype'] = 62
  1102.         kwarg['Switchtype'] = 18
  1103.         kwarg['Options'] = {"LevelActions": "|||", "LevelNames": "Off|Vibrate|Rotation|drop", "LevelOffHidden": "true", "SelectorStyle": "0"}
  1104.  
  1105.     elif _Type == 'ZHAThermostat' or _Type == 'CLIPThermostat':
  1106.         kwarg['Type'] = 242
  1107.         kwarg['Subtype'] = 1
  1108.  
  1109.     elif _Type == 'ZHAAlarm':
  1110.         kwarg['Type'] = 244
  1111.         kwarg['Subtype'] = 73
  1112.         kwarg['Switchtype'] = 2
  1113.  
  1114.     elif _Type == 'ZHAWater':
  1115.         kwarg['Type'] = 244
  1116.         kwarg['Subtype'] = 62
  1117.         kwarg['Switchtype'] = 5
  1118.         kwarg['Image'] = 11 # Visible only on floorplan
  1119.  
  1120.     elif _Type == 'ZHAFire' or _Type == 'ZHACarbonMonoxide':
  1121.         kwarg['Type'] = 244
  1122.         kwarg['Subtype'] = 62
  1123.         kwarg['Switchtype'] = 5
  1124.  
  1125.     elif _Type == 'CLIPGenericStatus':
  1126.         kwarg['TypeName'] = 'Text'
  1127.  
  1128.     elif _Type == 'CLIPGenericFlag':
  1129.         kwarg['Type'] = 244
  1130.         kwarg['Subtype'] = 62
  1131.         kwarg['Switchtype'] = 0
  1132.         kwarg['Image'] = 9
  1133.  
  1134.     #Switch
  1135.     elif _Type == 'Switch_Generic':
  1136.         kwarg['Type'] = 244
  1137.         kwarg['Subtype'] = 62
  1138.         kwarg['Switchtype'] = 18
  1139.         kwarg['Image'] = 9
  1140.         kwarg['Options'] = {"LevelActions": "||||||", "LevelNames": "Off|B1|B2|B3|B4|B5|B6|B7|B8", "LevelOffHidden": "true", "SelectorStyle": "0"}
  1141.  
  1142.     elif _Type == 'Tradfri_remote':
  1143.         kwarg['Type'] = 244
  1144.         kwarg['Subtype'] = 62
  1145.         kwarg['Switchtype'] = 18
  1146.         kwarg['Image'] = 9
  1147.         kwarg['Options'] = {"LevelActions": "|||||", "LevelNames": "Off|On|More|Less|Right|Left", "LevelOffHidden": "true", "SelectorStyle": "0"}
  1148.  
  1149.     elif _Type == 'Tradfri_on/off_switch':
  1150.         kwarg['Type'] = 244
  1151.         kwarg['Subtype'] = 62
  1152.         kwarg['Switchtype'] = 18
  1153.         kwarg['Options'] = {"LevelActions": "|||||", "LevelNames": "Off|B1C|B1L|B2C|B2L", "LevelOffHidden": "true", "SelectorStyle": "0"}
  1154.  
  1155.     elif _Type == 'XCube_C':
  1156.         kwarg['Type'] = 244
  1157.         kwarg['Subtype'] = 62
  1158.         kwarg['Switchtype'] = 18
  1159.         kwarg['Image'] = 9
  1160.         kwarg['Options'] = {"LevelActions": "||||||||", "LevelNames": "Off|Shak|Wake|Drop|90°|180°|Push|Tap", "LevelOffHidden": "true", "SelectorStyle": "0"}
  1161.  
  1162.     elif _Type == 'XCube_R':
  1163.         kwarg['TypeName'] = 'Custom'
  1164.         kwarg['Options'] = {"Custom": ("1;degree")}
  1165.  
  1166.     #groups
  1167.     elif _Type == 'LightGroup' or _Type == 'groups':
  1168.         kwarg['Type'] = 241
  1169.         kwarg['Subtype'] = 7
  1170.         kwarg['Switchtype'] = 7
  1171.         #if 'bulbs_group' in Images:
  1172.         #    kwarg['Image'] = Images['bulbs_group'].ID
  1173.  
  1174.     #Scenes
  1175.     elif _Type == 'Scenes':
  1176.         kwarg['Type'] = 244
  1177.         kwarg['Subtype'] = 62
  1178.         kwarg['Switchtype'] = 9
  1179.         kwarg['Image'] = 9
  1180.  
  1181.     else:
  1182.         Domoticz.Error("Unknow device type " + _Type )
  1183.         return
  1184.  
  1185.     kwarg['DeviceID'] = IEEE
  1186.     kwarg['Name'] = _Name
  1187.     kwarg['Unit'] = Unit
  1188.     Domoticz.Device(**kwarg).Create()
  1189.  
  1190.     Domoticz.Status("### Create Device " + IEEE + " > " + _Name + ' (' + _Type +') as Unit ' + str(Unit) )
Advertisement
Add Comment
Please, Sign In to add comment