Advertisement
JoshDi

plugin.py

Apr 1st, 2018
191
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #           Broadlink RM2 Python Plugin for Domoticz
  2. #
  3. #           Dev. Platform : Win10 x64 & Py 3.5.3 x86
  4. #
  5. #           Author:     zak45, 2017-2018
  6. #           1.1.0:  code compatible py  3.x
  7. #           2.0.0:  import from e-Control or any other ini file with similar structure
  8. #                   webserver for file transfer
  9. #                   Off action managed for generated devices
  10. #                   clean action to erase files from import folder
  11. #           3.0.0:  Add Remote Control device with custom codes on ini file
  12. #                   Broadlink lib to v 0.5.0: timeout error solved, Pad the payload for AES encryption (16) (TC2 switch), Add support for pure python AES implementation ...
  13. #           4.0.0:  Add eSensor / Smart plug / Multi plug devices
  14. #                       --> big thanks to deennoo to have provided test devices  : http://domo-attitude.fr
  15. #                   support for chinese char thanks to : https://zhougy0717.github.io/2017/07/31/Smart%20Home%20with%20Domoticz%20+%20BroadLink%20+%20Synology%20+%20Amazon%20Echo/
  16. #                   Change the way to retreive module by using 'site', no more 'copy' should be necessary specially for linux systems
  17. #                   Broadlink lib to v 0.6.0
  18. #                   socket.setdefaulttimeout put on comment as plugin framework is on trouble on onheartbeat(): even with other plugins.
  19. #
  20.  
  21. # Below is what will be displayed in Domoticz GUI under HW
  22. #
  23. """
  24. <plugin key="BroadlinkRM2" name="Broadlink RM2 with Kodi Remote" author="zak45" version="4.0.0" wikilink="http://www.domoticz.com/wiki/plugins/BroadlinkRM2.html" externallink="https://github.com/mjg59/python-broadlink">
  25.    <params>
  26.        <param field="Address" label="IP Address" width="200px" required="true" default="127.0.0.1"/>
  27.        <param field="Mode1" label="Mac" width="100px" required="true" default="000000000000"/>
  28.        <param field="Mode3" label="Device Type" width="250px" required="true"  default="DIS">
  29.            <options>
  30.                <option label= "Discovery" value="DIS"/>
  31.                <option label= "Remote Control RM2/RM mini3" value="RM2"/>
  32.                <option label= "Remote Control RM2/RM mini3 with Temperature device" value="RM2T"/>
  33.                <option label= "eSensor multi sensors A1" value="A1"/>
  34.                <option label= "SmartPlug 1" value="SP1"/>
  35.                <option label= "SmartPlug 2/3" value="SP2"/>
  36.                <option label= "SmartPlug 3S" value="SP3S"/>
  37.                <option label= "MultiPlug 1" value="MP1"/>
  38.            </options>
  39.        </param>
  40.        <param field="Mode2" label="Folder to store ini files (RM2/RM mini3)" width="300px" required="true" default="C:/BroadlinkRM2"/>
  41.        <param field="Mode4" label="Generate import Device (RM2/RM mini3)" width="75px">
  42.            <options>
  43.                <option label= "False" value="no"/>
  44.                <option label= "True" value="yes" default="True"/>
  45.            </options>
  46.        </param>
  47.        <param field="Mode5" label="Port for HTTP server (RM2/RM mini3)" width="50px" required="true" default="9000"/>
  48.        <param field="Mode6" label="Debug" width="75px">
  49.            <options>
  50.                <option label="True" value="Debug"/>
  51.                <option label="False" value="Normal"  default="True" />
  52.            </options>
  53.        </param>
  54.    </params>
  55. </plugin>
  56. """
  57. #
  58. # Main Import
  59. import Domoticz
  60. import configparser
  61. import datetime
  62. import time
  63. import codecs
  64. import subprocess
  65. import socket
  66. #
  67. #
  68. # Required for import: path is OS dependent
  69. # Python framework in Domoticz do not include OS dependent path
  70. #
  71. import site
  72. import sys
  73. import os
  74. path=''
  75. path=site.getsitepackages()
  76. for i in path:
  77.     sys.path.append(i)
  78. #
  79. import broadlink
  80. #
  81. isConnected = False
  82. numberDev = 2
  83. bypass = False
  84. temp = 0
  85. learnedCommand = "None"
  86. sendCommand = ""
  87. loadedCommand = ""
  88. nbUpdate = 1
  89. isRunning = False
  90. custom = ""
  91. clear = False
  92. RemoteCommand = ""
  93. state = True
  94. statemp1 = {}
  95. energy = 0
  96.  
  97. # Domoticz call back functions
  98. #
  99.  
  100. # Executed once at HW creation/ update. Can create up to 255 devices.
  101. def onStart():
  102.     global numberDev, nbUpdate
  103.  
  104.     if Parameters["Mode6"] == "Debug":
  105.         Domoticz.Debugging(1)
  106.  
  107.     if  (Parameters["Mode3"] == 'DIS'):
  108.         if ( 1 not in Devices):
  109.             Domoticz.Device(Name="Discovery",  Unit=1, Type=17, Image=2, Switchtype=17, Used=1).Create()
  110.         if ( 2 not in Devices):
  111.             Domoticz.Device(Name="Discovery Info",  Unit=2, TypeName="Text", Used=1).Create()
  112.  
  113.     elif (Parameters["Mode3"] == 'RM2T' or Parameters["Mode3"] == 'RM2'):
  114.         if ( 1 not in Devices ):
  115.             Options =   {   "LevelActions"  :"||||" ,
  116.                             "LevelNames"    :"Off|Learn|Test|Save|Reset" ,
  117.                             "LevelOffHidden":"true",
  118.                             "SelectorStyle" :"0"
  119.                          }
  120.             Domoticz.Device(Name="Command",  Unit=1, TypeName="Selector Switch", Switchtype=18, Image=12, Options=Options, Used=1).Create()
  121.  
  122.         if ( 2 not in Devices and Parameters["Mode3"] == 'RM2T'):
  123.             Domoticz.Device(Name="Temp",  Unit=2, TypeName="Temperature", Used=1).Create()
  124.  
  125.         if ( 254 not in Devices ):
  126.             Domoticz.Device(Name="Remote",  Unit=254, Type=17, Image=2, Switchtype=17, Used=1).Create()
  127.  
  128.         if ( 255 not in Devices and Parameters["Mode4"] == 'yes' ):
  129.             Options =   {   "LevelActions"  :"||||" ,
  130.                             "LevelNames"    :"Off|WebStart|Generate|Import|Clear" ,
  131.                             "LevelOffHidden":"true",
  132.                             "SelectorStyle" :"0"
  133.                          }
  134.             Domoticz.Device(Name="Import",  Unit=255, TypeName="Selector Switch", Switchtype=18, Image=12, Options=Options, Used=1).Create()
  135.  
  136.     elif  (Parameters["Mode3"] == 'SP1' or Parameters["Mode3"] == 'SP2' or Parameters["Mode3"] == 'SP3S'):
  137.         if ( 1 not in Devices ):
  138.             Domoticz.Device(Name=str(Parameters["Mode3"]),  Unit=1,TypeName="Switch", Image=1, Used=1).Create()
  139.         if Parameters["Mode3"] == 'SP3S':
  140.             if ( 2 not in Devices ):
  141.                 Domoticz.Device(Name=str(Parameters["Mode3"]),  Unit=2,TypeName="Usage", Used=1).Create()
  142.             if ( 3 not in Devices ):
  143.                 Domoticz.Device(Name=str(Parameters["Mode3"]),  Unit=3,TypeName="kWh", Used=1).Create()
  144.  
  145.     elif  (Parameters["Mode3"] == 'A1'):
  146.         if ( 1 not in Devices ):
  147.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - Status',  Unit=1,Type=17, Image=17, Switchtype=17, Used=1).Create()
  148.         if ( 2 not in Devices ):
  149.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - Temperature',  Unit=2,TypeName="Temperature", Used=1).Create()
  150.         if ( 3 not in Devices ):
  151.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - Humidity',  Unit=3,TypeName="Humidity", Used=1).Create()
  152.         if ( 4 not in Devices ):
  153.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - Air Quality',  Unit=4,TypeName="Air Quality", Used=1).Create()
  154.         if ( 5 not in Devices ):
  155.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - Noise',  Unit=5,TypeName="Sound Level", Used=1).Create()
  156.         if ( 6 not in Devices ):
  157.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - Light',  Unit=6,TypeName="Illumination", Used=1).Create()
  158.  
  159.     elif  (Parameters["Mode3"] == 'MP1'):
  160.         if ( 1 not in Devices ):
  161.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - Status',  Unit=1,TypeName="Switch",Image=9, Used=1).Create()
  162.         if ( 2 not in Devices ):
  163.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - plug1',  Unit=2,TypeName="Switch",Image=1, Used=1).Create()
  164.         if ( 3 not in Devices ):
  165.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - plug2',  Unit=3,TypeName="Switch",Image=1, Used=1).Create()
  166.         if ( 4 not in Devices ):
  167.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - plug3',  Unit=4,TypeName="Switch",Image=1, Used=1).Create()
  168.         if ( 5 not in Devices ):
  169.             Domoticz.Device(Name=str(Parameters["Mode3"]) + ' - plug4',  Unit=5,TypeName="Switch",Image=1, Used=1).Create()
  170.  
  171.  
  172.     DumpConfigToLog()
  173.     Domoticz.Heartbeat(30)
  174.  
  175.     numberDev = len(Devices) - 1
  176.     if (255 in Devices):
  177.         UpdateDevice(255, 0, 'Off')
  178.         numberDev = numberDev - 1
  179.  
  180.     Domoticz.Log("Connecting to: "+Parameters["Address"]+":"+Parameters["Mode1"])
  181.  
  182.     if Parameters["Mode3"] == 'RM2' or Parameters["Mode3"] == 'RM2T' or Parameters["Mode3"] == 'A1':
  183.         if not broadlinkConnect():
  184.             UpdateDevice(1, 0, 'Off')
  185.         else:
  186.             UpdateDevice(1, 1, '10')
  187.     elif Parameters["Mode3"] != 'DIS':
  188.         if checkPower():
  189.             if state:
  190.                 UpdateDevice(1, 1, 'On')
  191. #                if (Parameters["Mode3"] == 'MP1'):
  192. #                    AllPlugOn()
  193.             else:
  194.                 UpdateDevice(1, 0, 'Off')
  195. #                if (Parameters["Mode3"] == 'MP1'):
  196. #                    AllPlugOff()
  197.         else:
  198.             UpdateDevice(1, 0, 'Off')
  199. #            if (Parameters["Mode3"] == 'MP1'):
  200. #                    AllPlugOff()
  201.  
  202.     if Parameters["Mode3"] == 'RM2' or Parameters["Mode3"] == 'RM2T':
  203.         if not os.path.exists(Parameters["Mode2"] + "/import"):
  204.             os.makedirs(Parameters["Mode2"] + "/import")
  205.         if not os.path.exists(Parameters["Mode2"] + "/remote"):
  206.             os.makedirs(Parameters["Mode2"] + "/remote")
  207.  
  208.         genRemote()
  209.  
  210.     Domoticz.Log("Device Number begin to : "+ str(numberDev))
  211.  
  212.     return True
  213.  
  214. # executed each time we click on device thru domoticz GUI
  215. def onCommand(Unit, Command, Level, Hue):
  216.     global sendCommand, isRunning, learnedCommand, isConnected
  217.  
  218.     Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level) + " , Connected : " + str(isConnected))
  219.  
  220.     Command = Command.strip()
  221.  
  222.     if (Command == 'Set Level'):
  223.         if (Parameters["Mode3"] == 'RM2T' or Parameters["Mode3"] == 'RM2'):
  224.             if (Unit == 1):  # Command selector
  225.                 if (Level == 10):
  226.                         learn()
  227.                 if (Level == 20):
  228.                     sendCommand = learnedCommand
  229.                     if learnedCommand == "None":
  230.                         Domoticz.Log('Nothing to send')
  231.                     else:
  232.                         send()
  233.                 if (Level == 30):
  234.                     if learnedCommand == "None":
  235.                         Domoticz.Log('Nothing to save')
  236.                     else:
  237.                         custom = ""
  238.                         if save():
  239.                             UpdateDevice(1,1,'10')
  240.                             learnedCommand = "None"
  241.                 if (Level == 40):
  242.                     if learnedCommand == "None":
  243.                         Domoticz.Log('Nothing to reset')
  244.                     else:
  245.                         reset()
  246.             elif (Unit == 255):
  247.                 if (Level == 10):
  248.                     if startWeb():
  249.                         isRunning = True
  250.                         UpdateDevice(255,1,'10')
  251.                     else:
  252.                         UpdateDevice(255,0,'Off')
  253.                         Domoticz.Error ('Not able to start Web server')
  254.                 if (Level == 20):
  255.                     if createIniImport():
  256.                         UpdateDevice(255,1,'20')
  257.                     else:
  258.                         UpdateDevice(255,0,'Off')
  259.                         Domoticz.Error ('Error with json files to import')
  260.                 if (Level == 30):
  261.                     clear = False
  262.                     if manageIniImport(clear):
  263.                         UpdateDevice(255,1,'30')
  264.                     else:
  265.                         UpdateDevice(255,0,'Off')
  266.                 if (Level == 40):
  267.                     clear = True
  268.                     if manageIniImport(clear):
  269.                         UpdateDevice(255,1,'40')
  270.                     else:
  271.                         UpdateDevice(255,0,'Off')
  272.             else:
  273.                 Domoticz.Error('Unit unknown')
  274.  
  275.     elif (Command == 'On'):
  276.  
  277.         if (Unit == 1 and Parameters['Mode3'] == 'DIS'):  # Discovery
  278.             if Discover():
  279.                 UpdateDevice(Unit, 1, 'Found : ' + str(len(brodevices )) + ' device(s)')
  280.             else:
  281.                 Domoticz.Error('Not able to find Broadlink device')
  282.         elif (Unit==254 and RemoteCommand != "" ):
  283.             UpdateDevice(Unit, 1, 'On')
  284.         elif ( Unit==1 and (Parameters['Mode3'] == 'SP1' or Parameters['Mode3'] == 'SP2' or Parameters['Mode3'] == 'SP3S')):
  285.             try:
  286.                 device.set_power(True)
  287.                 UpdateDevice(Unit,1,'On')
  288.             except:
  289.                 Domoticz.Error(' error to put ON SP1/SP2/SP3 ')
  290.                 isConnected = False
  291.         elif (Parameters['Mode3'] == 'MP1'):
  292.             if ( Unit > 1 and Unit < 6):
  293.                 try:
  294.                     device.set_power(Unit - 1, True)
  295.                     UpdateDevice(Unit,1,'On')
  296.                 except:
  297.                     Domoticz.Error(' Error to put ON MP1 for plug : ' + str(Unit -1))
  298.         else:
  299.             if (Parameters["Mode3"] == 'RM2T' or Parameters["Mode3"] == 'RM2'):
  300.                 genCommand(Unit)
  301.             else:
  302.                 Domoticz.Error('Unknown command')
  303.  
  304.     elif (Command == 'Off'):
  305.  
  306.         if (Unit == 1 and Parameters['Mode3'] == 'DIS'):  # Discovery
  307.                 UpdateDevice(Unit, 0, 'Off')
  308.         elif ( Unit==1 and (Parameters['Mode3'] == 'SP1' or Parameters['Mode3'] == 'SP2' or Parameters['Mode3'] == 'SP3S')):
  309.             try:
  310.                 device.set_power(False)
  311.                 UpdateDevice(Unit,0,'Off')
  312.             except:
  313.                 Domoticz.Error(' error to put Off SP1/SP2/SP3 ')
  314.                 isConnected = False
  315.         elif (Parameters['Mode3'] == 'MP1'):
  316.             if ( Unit > 1 and Unit < 6):
  317.                 try:
  318.                     device.set_power(Unit - 1, False)
  319.                     UpdateDevice(Unit,0,'Off')
  320.                 except:
  321.                     Domoticz.Error(' Error to put Off MP1 for plug : ' + str(Unit -1))
  322.         else:
  323.             try:
  324.                 UpdateDevice(Unit, 0, 'Off')
  325.             except:
  326.                 Domoticz.Error('Unit error update')
  327.                 raise
  328.     elif ( Unit == 254):
  329.         if remoteSend(Command):
  330.             UpdateDevice(Unit, 1, Command)
  331.         else:
  332.             UpdateDevice(Unit, 1, 'undefined')
  333.  
  334.     else:
  335.         Domoticz.Error('Unknown command')
  336.  
  337.     return True
  338.  
  339. # execution depend of Domoticz.Heartbeat(x) x in seconds
  340. def onHeartbeat():
  341.     global bypass, isConnected, isRunning, state
  342.  
  343.     now = datetime.datetime.now()
  344.  
  345.     if (255 in Devices and isRunning == True):
  346.             isAlive()
  347.  
  348.     if bypass is True:
  349.         bypass = False
  350.         return
  351. # for RM2T type we check temp every 2 minutes
  352.     if Parameters["Mode3"] == 'RM2T':
  353.         if ((now.minute % 2) == 0):
  354.             bypass = True
  355.             if isConnected:
  356.                 if checkTemp():
  357.                     UpdateDevice(2, 1, temp)
  358.                     UpdateDevice(1,1,'10')
  359.                 else:
  360.                     isConnected = False
  361.                     UpdateDevice(1,0,'Off')
  362.             else:
  363.                 broadlinkConnect()
  364. # for A1 we get sensor data every 30 seconds
  365.     elif Parameters["Mode3"] == 'A1':
  366.         if Parameters["Mode6"] == "Debug":
  367.             Domoticz.Log(" A1 called")
  368.         if ((now.minute % 1) == 0):
  369.             bypass = False
  370.             if isConnected:
  371.                 if checkSensor():
  372.                     UpdateDevice(1, 1, 'Get Data From Sensors')
  373.                 else:
  374.                     isConnected = False
  375.             else:
  376.                 broadlinkConnect()
  377. # for SP3S we get energy/status data every 30 seconds
  378.     elif Parameters["Mode3"] == 'SP3S':
  379.         if Parameters["Mode6"] == "Debug":
  380.             Domoticz.Log(" SP3S called")
  381.         if ((now.minute % 1) == 0):
  382.             bypass = False
  383.             if isConnected:
  384.                 if getEnergy():
  385.                     UpdateDevice(2, 0, str(energy))
  386.                     UpdateDevice(3, 0, str(energy))
  387.                 else:
  388.                     isConnected = False
  389.                 if checkPower():
  390.                     if state:
  391.                         UpdateDevice(1, 1, 'On')
  392.                     else:
  393.                         UpdateDevice(1, 0, 'Off')
  394.                 else:
  395.                     isConnected = False
  396.             else:
  397.                 broadlinkConnect()
  398. # for MP1 we check status every 1 minute
  399. #    elif Parameters["Mode3"] == 'MP1':
  400. #        if Parameters["Mode6"] == "Debug":
  401. #            Domoticz.Log("MP1 called")
  402. #        if ((now.minute % 1) == 0):
  403. #            bypass = True
  404. #            if isConnected:
  405. #                if checkPower():
  406. #                    if statemp1:
  407. #                        UpdateDevice(1, 1, 'On')
  408. #                        AllPlugOn()
  409. #                    else:
  410. #                        UpdateDevice(1, 0, 'Off')
  411. #                        AllPlugOff()
  412. #                else:
  413. #                    isConnected = False
  414. #            else:
  415. #                broadlinkConnect()
  416. # for SP1/2 we check status every 1 minute
  417.     elif Parameters["Mode3"] == 'SP1' or Parameters["Mode3"] == 'SP2':
  418.         if Parameters["Mode6"] == "Debug":
  419.             Domoticz.Log("SP1/SP2 called")
  420.         if ((now.minute % 1) == 0):
  421.             bypass = True
  422.             if isConnected:
  423.                 if checkPower():
  424.                     if state:
  425.                         UpdateDevice(1, 1, 'On')
  426.                     else:
  427.                         UpdateDevice(1, 0, 'Off')
  428.                 else:
  429.                     isConnected = False
  430.             else:
  431.                 broadlinkConnect()
  432. # for DIS we do nothing
  433.     elif Parameters["Mode3"] == 'DIS':
  434.         return
  435. # for RM2 we try to connect every 5 minutes if checkTemp is False
  436.     else:
  437.         if (now.minute % 5 == 0):
  438.             if not checkTemp():
  439.                 UpdateDevice(1,0,'Off')
  440.                 if broadlinkConnect():
  441.                     UpdateDevice(1,1,'10')
  442.             bypass = True
  443.  
  444.     return True
  445.  
  446. # executed once when HW updated/removed
  447. def onStop():
  448.     Domoticz.Log("onStop called")
  449.     return True
  450.  
  451. # Generic helper functions
  452. def DumpConfigToLog():
  453.     for x in Parameters:
  454.         if Parameters[x] != "":
  455.             Domoticz.Debug( "'" + x + "':'" + str(Parameters[x]) + "'")
  456.     Domoticz.Debug("Device count: " + str(len(Devices)))
  457.     for x in Devices:
  458.         Domoticz.Debug("Device:           " + str(x) + " - " + str(Devices[x]))
  459.         Domoticz.Debug("Device ID:       '" + str(Devices[x].ID) + "'")
  460.         Domoticz.Debug("Device Name:     '" + Devices[x].Name + "'")
  461.         Domoticz.Debug("Device nValue:    " + str(Devices[x].nValue))
  462.         Domoticz.Debug("Device sValue:   '" + Devices[x].sValue + "'")
  463.         Domoticz.Debug("Device LastLevel: " + str(Devices[x].LastLevel))
  464.     return
  465.  
  466. # Update Device into DB
  467. def UpdateDevice(Unit, nValue, sValue):
  468.     # Make sure that the Domoticz device still exists (they can be deleted) before updating it
  469.     if (Unit in Devices):
  470.         if Unit == 1:
  471.             if (Devices[Unit].nValue != nValue) or (Devices[Unit].sValue != sValue):
  472.                 Devices[Unit].Update(nValue=nValue, sValue=str(sValue))
  473.                 Domoticz.Log("Update "+str(nValue)+":'"+str(sValue)+"' ("+Devices[Unit].Name+")")
  474.         else:
  475.             Devices[Unit].Update(nValue=nValue, sValue=str(sValue))
  476.             Domoticz.Log("Update "+str(nValue)+":'"+str(sValue)+"' ("+Devices[Unit].Name+")")
  477.     return
  478.  
  479. # generate command to execute and update name in ini file if necessary
  480. def genCommand(Unit):
  481.     global loadedCommand, sendCommand, nbUpdate
  482.  
  483.     Domoticz.Log('Generate on Command for learned code stored on unit/ini :' + str(Unit))
  484.  
  485.     path=str(Parameters["Mode2"]) + "/" + str(Parameters["Key"]) + "-" + str(Parameters["HardwareID"]) + "-" + str(Unit) + ".ini"
  486.  
  487.     if not os.path.exists(path):
  488.         Domoticz.Error(' ini file not found: ' + str(path))
  489.         return
  490.  
  491.     config = configparser.ConfigParser()
  492.     config.read(path,encoding='utf8')
  493.     loadedCommand = config.get("LearnedCode", str(Unit))
  494.     if Parameters["Mode6"] == "Debug":
  495.         Domoticz.Log(" Code loaded : " + loadedCommand)
  496.     sendCommand = loadedCommand
  497.     if isConnected:
  498.         send()
  499.     if Parameters["Mode6"] == "Debug":
  500.         Domoticz.Log(' <b> Command line : ' + '"' + Parameters['HomeFolder'] + 'plugin_send.py' +  '" ' + path + ' </b>')
  501.  
  502.     if Unit in Devices:
  503.         try:
  504.             UpdateDevice(Unit,1,'On-'+str(nbUpdate))
  505.             nbUpdate +=1
  506.         except:
  507.             Domoticz.Error("Not able to update device : " + str(Unit))
  508.  
  509.         try:
  510.             if not (Devices[Unit].Name == config.get("DEFAULT","customname")):
  511.  
  512.                 config.set('DEFAULT','customname',Devices[Unit].Name)
  513.  
  514.                 try:
  515.                     with open(path, 'w') as configfile:
  516.                         config.write(configfile)
  517.                 except IOError:
  518.                     Domoticz.Error('Error updating config file')
  519.                     raise
  520.         except:
  521.             Domoticz.Error('Error updating config file, customname param missing')
  522.             raise
  523.  
  524.     return
  525.  
  526. # save learned/imported code and create Domoticz device
  527. def save():
  528.     global path, learnedCommand, Unit, numberDev, custom
  529.  
  530.     numberDev +=1
  531.     path=str(Parameters["Mode2"]) + "/" + str(Parameters["Key"]) + "-" + str(Parameters["HardwareID"]) + "-" + str(numberDev) + ".ini"
  532.  
  533.     if os.path.exists(path):
  534.         Domoticz.Error('File exist : ' + path)
  535.         return False
  536.     else:
  537.         try:
  538.             create_config(path,str(numberDev),learnedCommand,custom)
  539.         except:
  540.             Domoticz.Error('Not able to create : ' + path)
  541.             return False
  542.     try:
  543.         Domoticz.Device(Name=str(Parameters["HardwareID"])+"-" + str(numberDev)+ " " + custom,  Unit=numberDev, TypeName="Selector Switch", Type=244, Switchtype=9, Subtype=73).Create()
  544.     except:
  545.         Domoticz.Error('Not able to create device')
  546.         return False
  547.  
  548.     if Parameters["Mode6"] == "Debug":
  549.         Domoticz.Log(' <b> Command line : ' + '"' + Parameters['HomeFolder'] + 'plugin_send.py' +  '" ' + path + ' </b>')
  550.  
  551.     return True
  552.  
  553. def reset():
  554.     global learnedCommand
  555.  
  556.     UpdateDevice(1, 0, 'Off')
  557.     learnedCommand = "None"
  558.     if Parameters["Mode6"] == "Debug":
  559.         Domoticz.Log("Reset learned command")
  560.  
  561.     return True
  562.  
  563. # discover Broadlink device on the Network
  564. def Discover():
  565.     global brodevices
  566.  
  567.     Domoticz.Log("All plugin system is on pause for 5s...")
  568.     brodevices = broadlink.discover(timeout=5)
  569.     Domoticz.Log("Found " + str(len(brodevices )) + " broadlink devices")
  570.  
  571.     if str(len(brodevices )) == 0:
  572.         return False
  573.  
  574.     txtdevice = ''
  575.  
  576.     for index, item in enumerate(brodevices):
  577.  
  578.         brodevices[index].auth()
  579.  
  580.         broip = brodevices[index].host
  581.         broip = str(broip)
  582.         Domoticz.Log( "<b>Device " + str(index + 1) +" Host address = " + broip[1:19] + "</b>")
  583.         txtdevice = txtdevice + "[Device " + str(index + 1) +" Host address = " + broip[1:19] + "]"
  584.         macadd = ''.join(format(x, '02x') for x in brodevices[index].mac[::-1])
  585.         macadd = str(macadd)
  586.         brotype = str(brodevices[index].type)
  587.         Domoticz.Log( "<b>Device " + str(index + 1) +" MAC address = " + macadd + " Type: " + brotype + "</b>")
  588.         txtdevice = txtdevice + "[Device " + str(index + 1) +" MAC address = " + macadd + " Type: " + brotype + "]"
  589.         if len(txtdevice) > 200:txtdevice=txtdevice[0:197] + '...'
  590.  
  591.     UpdateDevice(2,1,txtdevice)
  592.  
  593.     return True
  594.  
  595. # Put Broadlink on Learn , packet received converted to Hex
  596. def learn():
  597.     global learnedCommand
  598.  
  599.     if not isConnected:
  600.         broadlinkConnect()
  601.  
  602.     Domoticz.Log("All plugin system is on pause for 5s...")
  603.     Domoticz.Log("When Broadlink led is lit press the button on your remote within 5 seconds")
  604.  
  605.     try:
  606.         device.enter_learning()
  607.     except:
  608.         Domoticz.Error ('Not able to learn command')
  609.         return False
  610.  
  611.     time.sleep(5)
  612.  
  613.     ir_packet = device.check_data()
  614.     if Parameters["Mode6"] == "Debug":
  615.         Domoticz.Log(str(ir_packet))
  616.  
  617.     if str(ir_packet) == "None":
  618.         Domoticz.Log('Command not received')
  619.         learnedCommand= "None"
  620.         return False
  621.  
  622.     learnedCommand=(codecs.encode(ir_packet, 'hex_codec')).decode('utf-8')
  623.     if Parameters["Mode6"] == "Debug":
  624.         Domoticz.Log(learnedCommand)
  625.  
  626.     Domoticz.Log( "Code stored in memory" )
  627.     UpdateDevice(1, 1, '20')
  628.  
  629.     return True
  630.  
  631. # send Hex command
  632. def send():
  633.     global sendCommand
  634.  
  635.     if not sendCommand:
  636.         Domoticz.Error('Nothing to send')
  637.         return False
  638.  
  639.     sendCommand = bytes.fromhex(sendCommand)
  640.     if Parameters["Mode6"] == "Debug":
  641.         Domoticz.Log(str(sendCommand))
  642.  
  643.     try:
  644.         device.send_data(sendCommand)
  645.         Domoticz.Log( "Code Sent....")
  646.     except:
  647.         Domoticz.Error( "Code Sent WARNING....Probably timeout")
  648.         return False
  649.  
  650.     return True
  651.  
  652. #Create a config file
  653. def create_config(path,Unit,learnedCommand,custom):
  654.  
  655.     config = configparser.ConfigParser()
  656.     config['DEFAULT'] = {   'PluginKey'     : Parameters["Key"],
  657.                             'PluginName'    : Parameters["Name"],
  658.                             'PluginFolder'  : Parameters["HomeFolder"],
  659.                             'HardwareID'    : Parameters["HardwareID"],
  660.                             'Unit'          : Unit,
  661.                             'CustomName'    : custom
  662.                         }
  663.  
  664.     config['Device'] = {    'Host'  : Parameters["Address"],
  665.                             'Mac'   : Parameters["Mode1"]
  666.                         }
  667.     config['LearnedCode'] = {}
  668.     UniteCode = config['LearnedCode']
  669.     UniteCode[str(Unit)] = learnedCommand
  670.     try:
  671.         with open(path, 'w') as configfile:
  672.             config.write(configfile)
  673.     except IOError:
  674.         Domoticz.Error('Error create config file')
  675.         raise
  676.  
  677.     if Parameters["Mode6"] == "Debug":
  678.         Domoticz.Log( "ini file creation...." + path)
  679.  
  680.     return
  681.  
  682. # connect to Broadlink
  683. def broadlinkConnect():
  684.     global device, isConnected
  685.  
  686.     try:
  687.         if (Parameters["Mode3"] == 'RM2T'  or Parameters["Mode3"] == 'RM2'):
  688.             device = broadlink.rm(host=(Parameters["Address"],80), mac=bytearray.fromhex(Parameters["Mode1"]), devtype=0x279d)
  689.         elif (Parameters["Mode3"] == 'A1'):
  690.             device = broadlink.a1(host=(Parameters["Address"],80), mac=bytearray.fromhex(Parameters["Mode1"]), devtype=0x2714)
  691.         elif (Parameters["Mode3"] == 'SP1'):
  692.             device = broadlink.sp1(host=(Parameters["Address"],80), mac=bytearray.fromhex(Parameters["Mode1"]), devtype=0)
  693.         elif (Parameters["Mode3"] == 'SP2' or Parameters["Mode3"] == 'SP3S'):
  694.             device = broadlink.sp2(host=(Parameters["Address"],80), mac=bytearray.fromhex(Parameters["Mode1"]), devtype=0x2711)
  695.         elif (Parameters["Mode3"] == 'MP1'):
  696.             device = broadlink.mp1(host=(Parameters["Address"],80), mac=bytearray.fromhex(Parameters["Mode1"]), devtype=0x4EB5)
  697.         else:
  698.             device = 'unknown'
  699.         device.auth()
  700.         device.host
  701.         isConnected = True
  702.         Domoticz.Log( "Connected to Broadlink device: " + str(Parameters["Address"]))
  703.     except:
  704.         Domoticz.Error( "Error Connecting to Broadlink device...." + str(Parameters["Address"]))
  705.         isConnected = False
  706.         return False
  707.  
  708.     return True
  709.  
  710. # get temperature for RM2T
  711. def checkTemp():
  712.     global temp
  713.  
  714.     try:
  715.         temp=device.check_temperature()
  716.     except:
  717.         Domoticz.Error( "Error getting temperature data from Broadlink device....Timeout")
  718.         return False
  719.  
  720.     if temp > 60:
  721.         return False
  722.  
  723.     return True
  724.  
  725. # Start Web server for Transfert for RM2/RM2T
  726. def startWeb():
  727.  
  728.     if sys.platform.startswith('linux'):
  729.     # linux specific code here
  730.         cmdFile = Parameters["HomeFolder"] + 'plugin_http.sh'
  731.     elif sys.platform.startswith('darwin'):
  732.     # mac
  733.         cmdFile = Parameters["HomeFolder"] + 'plugin_http.sh'
  734.     elif sys.platform.startswith('win32'):
  735.     #  win specific
  736.         cmdFile = '"' + Parameters["HomeFolder"] + 'plugin_http.cmd' + '"'
  737.  
  738.     commandtoexecute =  cmdFile + " 0.0.0.0 " + Parameters["Mode5"] + " " + Parameters["Mode2"]
  739.  
  740.     try:
  741.         subprocess.check_call(commandtoexecute, shell=True, timeout=2)
  742.     except subprocess.CalledProcessError as e:
  743.         Domoticz.Error(str(e.returncode))
  744.         Domoticz.Error(str(e.cmd))
  745.         Domoticz.Error(str(e.output))
  746.         return False
  747.  
  748.     if Parameters["Mode6"] == "Debug":
  749.         Domoticz.Log("Subprocess " + commandtoexecute + " launched...")
  750.  
  751.     return True
  752.  
  753. # check Webserver is running, if not put device Off
  754. def isAlive():
  755.     global isRunning
  756.  
  757.     socket.setdefaulttimeout(2)
  758.     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  759.  
  760.     try:
  761.         s.connect(('127.0.0.1', int(Parameters["Mode5"])))
  762.         isRunning = True
  763.         s.sendall(b"GET /")
  764.     except socket.error as e:
  765.         isRunning = False
  766.         UpdateDevice(255,0,'Off')
  767.  
  768.     s.close()
  769.     if Parameters["Mode6"] == "Debug":
  770.             Domoticz.Log("Web isAlive status :" +str(isRunning))
  771.  
  772.     return
  773.  
  774. #import json files and transfrom to ini file and hex imported code for RM2/RM2T
  775. def createIniImport():
  776.     global learnedCommand, custom
  777.  
  778.     import json
  779.  
  780.     path=Parameters["Mode2"] + "/import/"
  781.  
  782.     try:
  783.         with open(path+"jsonSubIr", encoding='utf8') as remote_name:
  784.             data_remote = json.load(remote_name)
  785.     except ValueError: # includes simplejson.decoder.JSONDecodeError
  786.         return False
  787.  
  788.     try:
  789.         with open(path+"jsonButton", encoding='utf8') as button_name:
  790.             data_button = json.load(button_name)
  791.     except ValueError: # includes simplejson.decoder.JSONDecodeError
  792.         return False
  793.  
  794.     try:
  795.         with open(path+"jsonIrCode", encoding='utf8') as code_name:
  796.             data_code = json.load(code_name)
  797.     except ValueError: # includes simplejson.decoder.JSONDecodeError
  798.         return False
  799.  
  800.     recCode = open(path+"simulate.txt", 'w')
  801.     CRLF="\n"
  802.  
  803.     for i in range(0, len(data_code)):
  804.         button = data_code[i]['buttonId']
  805.         for j in range(0, len(data_button)):
  806.             if data_button[j]['id'] == button:
  807.                 numName = data_button[j]['subIRId']
  808.                 buttonName = data_button[j]['name']
  809.                 for k in range(0, len(data_remote)):
  810.                     if data_remote[k]['id'] == numName:
  811.                         name = data_remote[k]['name']
  812.                         break
  813.                     else:
  814.                         name = "unknown"
  815.                 break
  816.             else:
  817.                 buttonName = "unknown"
  818.  
  819.         code = ''.join('%02x' % (i & 0xff) for i in data_code[i]['code'])
  820.         result = "Numrec : " + str(i) + " Button number: " + str(button ) + " " + "Number name : " + str(numName) + " Name : " + name + " " + buttonName + " Code : " + str(code)
  821.         custom = name + " " + buttonName
  822.         path = Parameters["Mode2"] + "/import/" + "IMP-" + str(i) + ".ini"
  823.  
  824.         create_config(path,i,code,custom)
  825.         recCode.writelines(result+CRLF)
  826.  
  827.         if Parameters["Mode6"] == "Debug":
  828.             Domoticz.Log(result)
  829.  
  830.     filelink = "file://" +  Parameters["Mode2"] + "/import/" + "simulate.txt"
  831.     Domoticz.Log("Number of devices to create : " + str( i + 1 ))
  832.     Domoticz.Log("You need to select Import for that")
  833.     Domoticz.Log('Simulate.txt file has been created with all codes on it. Click <a target="_blank"  href="' + filelink + '" style="color:blue">here</a> to see the path')
  834.  
  835.     return True
  836.  
  837. # if clear is True we will erase all files, if False we will create devices and erase ini files
  838. def manageIniImport(clear):
  839.     global custom, learnedCommand
  840.  
  841.     import glob
  842.     import errno
  843.  
  844.     path = Parameters["Mode2"] + "/import/*.ini"
  845.     files = glob.glob(path)
  846.  
  847.     if not files:
  848.         Domoticz.Log("No ini files found")
  849.         if clear == False:
  850.             return False
  851.     else:
  852.         for name in files: # 'file' is a builtin type, 'name' is a less-ambiguous variable name.
  853.             if clear == False:
  854.                 try:
  855.                     with open(name) as f: # No need to specify 'r': this is the default.
  856.                         config = configparser.ConfigParser()
  857.                         config.read(name,encoding='utf8')
  858.                         UnitNumber=config.get("DEFAULT", "unit")
  859.                         custom=config.get("DEFAULT", "customname")
  860.                         learnedCommand = config.get("LearnedCode", str(UnitNumber))
  861.                         createDev()
  862.                 except IOError as exc:
  863.                     if exc.errno != errno.EISDIR: # Do not fail if a directory is found, just ignore it.
  864.                         raise # Propagate other kinds of IOErro
  865.             os.remove(name)
  866.             if Parameters["Mode6"] == "Debug":
  867.                 Domoticz.Log(name + "  removed")
  868.  
  869.     if clear == True:
  870.         path = Parameters["Mode2"] + "/import/json*"
  871.         files = glob.glob(path)
  872.         if not files:
  873.             Domoticz.Log("No json files found")
  874.             return False
  875.         else:
  876.             for name in files:
  877.                 os.remove(name)
  878.                 if Parameters["Mode6"] == "Debug":
  879.                     Domoticz.Log(name + "  removed")
  880.  
  881.     return True
  882.  
  883. def createDev():
  884.  
  885.     if not save() and numberDev < 254:
  886.         createDev()
  887.  
  888.     return
  889.  
  890. def remoteSend(Command):
  891.  
  892.     if Command in remoteKEY:
  893.         k = remoteKEY.index(Command)
  894.         try:
  895.             genCommand(remotetoSEND[k])
  896.         except IndexError:
  897.             Domoticz.Error('Send error or Remote command not set in ini file: ' + Command)
  898.             return False
  899.         if Parameters["Mode6"] == "Debug":
  900.             Domoticz.Log('Remote send: ' + str(k+1) + " " + str(remotetoSEND[k]))
  901.     else:
  902.         Domoticz.Error('Remote command not defined: ' + Command)
  903.         return False
  904.  
  905.     return True
  906.  
  907. # get config ini file
  908. def get_remoteconfig():
  909.     global RemoteCommand
  910.  
  911.     name = Parameters["Mode2"] + "/remote/plugin_remote_"+ str(Parameters["HardwareID"]) + ".ini"
  912.  
  913.     if os.path.isfile(name):
  914.         try:
  915.             with open(name) as f: # No need to specify 'r': this is the default.
  916.                         config = configparser.ConfigParser()
  917.                         config.read(name,encoding='utf8')
  918.                         RemoteCommand = config.get("Custom", "Command")
  919.         except IOError as exc:
  920.             Domoticz.Error('error : ' + str(exc))
  921.             raise # Propagate other kinds of IOErro
  922.  
  923.         if Parameters["Mode6"] == "Debug":
  924.             Domoticz.Log( "ini file read...." + name)
  925.             Domoticz.Log( "Custom Commands: " + RemoteCommand)
  926.     else:
  927.         if Parameters["Mode6"] == "Debug":
  928.             Domoticz.Log( "No ini file :" + name)
  929.             Domoticz.Log( "Custom Commands for Remote not managed")
  930.  
  931.     return
  932.  
  933. # generate tuple for remote
  934. def genRemote():
  935.     global remoteKEY, remotetoSEND
  936.  
  937.     from ast import literal_eval as make_tuple
  938.  
  939.     get_remoteconfig()
  940.  
  941.     if RemoteCommand:
  942.         remotetoSEND = make_tuple(RemoteCommand)
  943.  
  944.     remoteKEY=( "Home",
  945.                 "Up",
  946.                 "Info",
  947.                 "Left",
  948.                 "Select",
  949.                 "Right",
  950.                 "Back",
  951.                 "Down",
  952.                 "ContextMenu",
  953.                 "ChannelUp",
  954.                 "FullScreen",
  955.                 "VolumeUp",
  956.                 "Channels",
  957.                 "ShowSubtitles",
  958.                 "Mute",
  959.                 "ChannelDown",
  960.                 "Stop",
  961.                 "VolumeDown",
  962.                 "BigStepBack",
  963.                 "Rewind",
  964.                 "PlayPause",
  965.                 "FastForward",
  966.                 "BigStepForward"
  967.                 )
  968.  
  969.     return
  970.  
  971. # retreive sensors data and update devices  for type A1
  972. def checkSensor():
  973.  
  974. # data
  975.     try:
  976.         data=device.check_sensors()
  977.     except:
  978.         Domoticz.Error( "Error getting sensor data from Broadlink device....Timeout")
  979.         return False
  980.  
  981.     if Parameters["Mode6"] == "Debug":
  982.         Domoticz.Log(str(data))
  983.  
  984. # raw data
  985.     try:
  986.         data_raw=device.check_sensors_raw()
  987.     except:
  988.         Domoticz.Error( "Error getting sensor data raw from Broadlink device....Timeout")
  989.         return False
  990.  
  991.     if Parameters["Mode6"] == "Debug":
  992.         Domoticz.Log(str(data_raw))
  993.  
  994. # temperature
  995.     tem =  data['temperature']
  996.  
  997.     UpdateDevice(2,0,str(tem))
  998.  
  999. # humidity
  1000.     hum =  data['humidity']
  1001.     if hum < 50:
  1002.         hum_raw = "0"
  1003.     elif hum < 60:
  1004.         hum_raw = "1"
  1005.     elif hum < 70:
  1006.         hum_raw = "2"
  1007.     else:
  1008.         hum_raw = "3"
  1009.  
  1010.     UpdateDevice(3,int(hum),hum_raw)
  1011.  
  1012. # air quality
  1013.     air =  data['air_quality']
  1014.     air_raw = data_raw['air_quality']
  1015.     if air_raw == 0:
  1016.         air_raw = 400
  1017.     elif air_raw == 1:
  1018.         air_raw = 800
  1019.     elif air_raw == 2:
  1020.         air_raw = 1000
  1021.     elif air_raw == 3:
  1022.         air_raw = 1800
  1023.     else:
  1024.         air_raw = 2800
  1025.  
  1026.     UpdateDevice(4,int(air_raw),str(air))
  1027.  
  1028. # noise
  1029.     noi =  data['noise']
  1030.     noi_raw = data_raw['noise']
  1031.     if noi_raw == 0:
  1032.         noi_raw = 20
  1033.     elif noi_raw == 1:
  1034.         noi_raw = 60
  1035.     elif noi_raw == 2:
  1036.         noi_raw = 80
  1037.     else:
  1038.         noi_raw = 120
  1039.  
  1040.     UpdateDevice(5,0,int(noi_raw))
  1041.  
  1042. # illimunation
  1043.     lux =  data['light']
  1044.     lux_raw = data_raw['light']
  1045.     if lux_raw == 0:
  1046.         lux_raw = 10
  1047.     elif lux_raw == 1:
  1048.         lux_raw = 200
  1049.     elif lux_raw == 2:
  1050.         lux_raw = 400
  1051.     elif lux_raw == 3:
  1052.         lux_raw = 800
  1053.     else:
  1054.         lux_raw = 1600
  1055.  
  1056.     UpdateDevice(6,0,int(lux_raw))
  1057.  
  1058.  
  1059.     return True
  1060.  
  1061. # SP1/2/3 devices
  1062. def checkPower():
  1063.     global state
  1064.  
  1065.     try:
  1066.         state = device.check_power()
  1067.         if Parameters["Mode6"] == "Debug":
  1068.             Domoticz.Log( ' Power state : ' + str(state))
  1069.     except:
  1070.         Domoticz.Error ('check power error')
  1071.         return False
  1072.  
  1073.     return True
  1074.  
  1075. # MP1 Device
  1076. def checkPowerMP1():
  1077.     global statemp1
  1078.  
  1079.     statemp1 = {}
  1080.  
  1081.     try:
  1082.         statemp1 = device.check_power()
  1083.         if Parameters["Mode6"] == "Debug":
  1084.             Domoticz.Log( ' Power state : ' + str(statemp1))
  1085.     except:
  1086.         Domoticz.Error ('MP1 check power error')
  1087.         return False
  1088.  
  1089.     return True
  1090.  
  1091. # SP3s device (SP2)
  1092. def getEnergy():
  1093.     global energy
  1094.  
  1095.     try:
  1096.         energy = device.get_energy()
  1097.         if Parameters["Mode6"] == "Debug":
  1098.             Domoticz.Log( ' Energy : ' + str(energy))
  1099.     except:
  1100.         Domoticz.Error ('Get Energy error')
  1101.         return False
  1102.  
  1103.     return True
  1104.  
  1105. # we put all switchs of the MP1 device to Off
  1106. def AllPlugOff():
  1107.  
  1108.     UpdateDevice (2,0,'Off')
  1109.     UpdateDevice (3,0,'Off')
  1110.     UpdateDevice (4,0,'Off')
  1111.     UpdateDevice (5,0,'Off')
  1112.  
  1113.     return
  1114.  
  1115. # we put all switchs of the MP1 device to On
  1116. def AllPlugOn():
  1117.  
  1118.     UpdateDevice (2,1,'On')
  1119.     UpdateDevice (3,1,'On')
  1120.     UpdateDevice (4,1,'On')
  1121.     UpdateDevice (5,1,'On')
  1122.  
  1123.     return
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement