├── readmeAssets ├── mit.png ├── set.png ├── howto.png ├── read.png ├── changes.png ├── consumption.png ├── devoloAPI.jpg └── requirements.png ├── ExtendedLogs ├── DHClogs.jpg ├── DHCbatteries.json ├── cronLog.php ├── README.md ├── DHCconsumptions.json └── showLog.html ├── examples.php ├── LICENSE ├── dev ├── README.md └── phpDevoloAPI.php ├── localConnection ├── README.md └── localphpdevoloAPI.php ├── README.md └── class └── phpDevoloAPI.php /readmeAssets/mit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiboOst/php-devoloDHC/HEAD/readmeAssets/mit.png -------------------------------------------------------------------------------- /readmeAssets/set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiboOst/php-devoloDHC/HEAD/readmeAssets/set.png -------------------------------------------------------------------------------- /readmeAssets/howto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiboOst/php-devoloDHC/HEAD/readmeAssets/howto.png -------------------------------------------------------------------------------- /readmeAssets/read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiboOst/php-devoloDHC/HEAD/readmeAssets/read.png -------------------------------------------------------------------------------- /ExtendedLogs/DHClogs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiboOst/php-devoloDHC/HEAD/ExtendedLogs/DHClogs.jpg -------------------------------------------------------------------------------- /readmeAssets/changes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiboOst/php-devoloDHC/HEAD/readmeAssets/changes.png -------------------------------------------------------------------------------- /readmeAssets/consumption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiboOst/php-devoloDHC/HEAD/readmeAssets/consumption.png -------------------------------------------------------------------------------- /readmeAssets/devoloAPI.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiboOst/php-devoloDHC/HEAD/readmeAssets/devoloAPI.jpg -------------------------------------------------------------------------------- /readmeAssets/requirements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiboOst/php-devoloDHC/HEAD/readmeAssets/requirements.png -------------------------------------------------------------------------------- /ExtendedLogs/DHCbatteries.json: -------------------------------------------------------------------------------- 1 | { 2 | "22.11.2017": { 3 | "WallSwitch_1": 62, 4 | "WallSwitch_2": 48, 5 | "MoveSensor": 98, 6 | "OpeningSensor": 96 7 | }, 8 | "21.11.2017": { 9 | "WallSwitch_1": 62, 10 | "WallSwitch_2": 48, 11 | "MoveSensor": 98, 12 | "OpeningSensor": 100 13 | }, 14 | "20.11.2017": { 15 | "WallSwitch_1": 62, 16 | "WallSwitch_2": 48, 17 | "MoveSensor": 98, 18 | "OpeningSensor": 100 19 | }, 20 | "19.11.2017": { 21 | "WallSwitch_1": 68, 22 | "WallSwitch_2": 48, 23 | "MoveSensor": 98, 24 | "OpeningSensor": 100 25 | }, 26 | "18.11.2017": { 27 | "WallSwitch_1": 68, 28 | "WallSwitch_2": 48, 29 | "MoveSensor": 100, 30 | "OpeningSensor": 100 31 | }, 32 | "17.11.2017": { 33 | "WallSwitch_1": 68, 34 | "WallSwitch_2": 48, 35 | "MoveSensor": 100, 36 | "OpeningSensor": 100 37 | } 38 | } -------------------------------------------------------------------------------- /examples.php: -------------------------------------------------------------------------------- 1 | error)) die($_DHC->error); 14 | 15 | 16 | //function to toggle the state or a rule: 17 | function toggleRule($ruleName) 18 | { 19 | global $_DHC; 20 | $isActive = $_DHC->isRuleActive($ruleName)['result']; 21 | 22 | if($isActive=='inactive') 23 | { 24 | $_DHC->turnRuleOnOff($ruleName, 1); 25 | } 26 | else 27 | { 28 | $_DHC->turnRuleOnOff($ruleName, 0); 29 | } 30 | } 31 | //then simply call toggleRule('myRule')! 32 | 33 | 34 | 35 | //Turn a light (wall plug) on: 36 | $_DHC->turnDeviceOnOff('myLight', 1); 37 | 38 | //Check if a device is on: 39 | $state = $DHC->isDeviceOn('My Wall Plug')['result']; 40 | 41 | //Start a scene: 42 | $_DHC->startScene('We go out'); 43 | 44 | 45 | 46 | ?> -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 KiboOst 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ExtendedLogs/cronLog.php: -------------------------------------------------------------------------------- 1 | error)) die($_DHC->error); 18 | 19 | //log Devolo Wall Plugs Consumptions: 20 | $_DHC->logConsumption($consumptionsLogPath); 21 | 22 | //log Devolo batteries levels: 23 | logBatteries($batteriesLogPath); 24 | 25 | 26 | function logBatteries($filePath='/') //@log file path | always @return['result'] array of yesterday total consumptions, @return['error'] if can't write file 27 | { 28 | global $_DHC; 29 | 30 | if (@file_exists($filePath)) 31 | { 32 | $prevDatas = json_decode(file_get_contents($filePath), true); 33 | } 34 | else 35 | { 36 | $prevDatas = array(); 37 | } 38 | 39 | //get today sums for each device: 40 | $today = date('d.m.Y'); 41 | $datasArray = array(); 42 | 43 | $BatLevels = $_DHC->getAllBatteries(); 44 | 45 | foreach ($BatLevels['result'] as $device) 46 | { 47 | $name = $device['name']; 48 | $level = $device['battery_percent']; 49 | $datasArray[$today][$name] = $level; 50 | } 51 | 52 | ksort($datasArray[$today]); 53 | 54 | //add today to previously loaded datas: 55 | $prevDatas[$today] = $datasArray[$today]; 56 | 57 | //set recent up: 58 | $keys = array_keys($prevDatas); 59 | usort($keys, 'sortByDate'); 60 | $newArray = array(); 61 | foreach ($keys as $key) 62 | { 63 | $newArray[$key] = $prevDatas[$key]; 64 | } 65 | $prevDatas = $newArray; 66 | 67 | //write it to file: 68 | @$put = file_put_contents($filePath, json_encode($prevDatas, JSON_PRETTY_PRINT)); 69 | if ($put) return array('result'=>$datasArray); 70 | return array('result'=>$datasArray, 'error'=>'Unable to write file!'); 71 | } 72 | 73 | function sortByDate($a, $b) 74 | { 75 | $t1 = strtotime($a); 76 | $t2 = strtotime($b); 77 | return ($t2 - $t1); 78 | } 79 | ?> -------------------------------------------------------------------------------- /dev/README.md: -------------------------------------------------------------------------------- 1 | # php-devoloDHC dev version 2 | 3 | Dev version to help supporting more devices inside Devolo Home Control. 4 | 5 | Not having myself these devices, I can't fully test them, or would need co-user invitation from users having them. If you have unsupported devices, you can help testing this version. 6 | 7 | ## Feature development 8 | 9 | - Philips Hue support 10 | 11 | 12 | 13 | ## How-to 14 | 15 | - See [*stable version How-To*](../../../../php-devoloDHC#how-to) for getting it running. 16 | - Replace stable version by dev version. 17 | 18 | 19 | 20 | ## Features to test 21 | 22 | Philips Hue: 23 | 24 | ```php 25 | //get HSB values of Hue: 26 | $_DHC->getHueHSB('myHue') 27 | 28 | //get RGB values of Hue: 29 | $_DHC->getHueRGB('myHue') 30 | 31 | //set RGB values: 32 | $_DHC->setHueRGB('myHue', array(128, 128, 128)) 33 | 34 | //turn Hue on/off (0/1): 35 | $_DHC->turnDeviceOnOff('myHue', 1) 36 | ``` 37 | 38 | #### Unsupported device 39 | 40 | If you have unsupported device, you can call special function with this device and post the return in a new issue. 41 | 42 | [Request for unsupported device](../../issues/) 43 | 44 | ```php 45 | $help = $DHC->debugDevice('MyStrangeDevice'); 46 | ``` 47 | 48 | 49 | 50 | ## Changes 51 | 52 | #### v 2.7dev (2017-05-16) 53 | - New: getHueHSB() / getHueRGB() / setHueRGB() 54 | - This version is identical to v2.63 with Hue support testing. 55 | 56 | 57 | 58 | ## License 59 | 60 | The MIT License (MIT) 61 | 62 | Copyright (c) 2017 KiboOst 63 | 64 | Permission is hereby granted, free of charge, to any person obtaining a copy 65 | of this software and associated documentation files (the "Software"), to deal 66 | in the Software without restriction, including without limitation the rights 67 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 68 | copies of the Software, and to permit persons to whom the Software is 69 | furnished to do so, subject to the following conditions: 70 | 71 | The above copyright notice and this permission notice shall be included in all 72 | copies or substantial portions of the Software. 73 | 74 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 75 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 76 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 77 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 78 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 79 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 80 | SOFTWARE. 81 | -------------------------------------------------------------------------------- /ExtendedLogs/README.md: -------------------------------------------------------------------------------- 1 | # php-devoloDHC 2 | 3 | ## Extended logs viewer from php Devolo API 4 | 5 | Here is a how-to to get your devices consumptions and battery levels visual feedback. 6 | 7 |

8 | 9 |

10 | 11 | ## Requirements 12 | - [Php Devolo API ready to run](https://github.com/KiboOst/php-devoloDHC) 13 | - cronLog.php 14 | - showLog.html 15 | - Display is supported thanks to [jQuery](https://jquery.com/) and [plotly](https://plot.ly/), both linked on their CDN (nothing to install/download) 16 | 17 | DHCbatteries.json and DHCconsumptions.json are examples provided to test your setup. Of course you will need your own logs :wink: 18 | 19 | 20 | ## Get logs 21 | 22 | You will have to log consumptions and battery levels everyday. 23 | - Download cronLog.php on your server 24 | - Edit cronLog.php so it can login to your Devolo DHC and change paths for both consumption and battery logs: 25 | 26 | ```php 27 | //logs paths: 28 | $consumptionsLogPath = $_SERVER['DOCUMENT_ROOT'].'/path/to/DHCconsumptions.json'; 29 | $batteriesLogPath = $_SERVER['DOCUMENT_ROOT'].'/path/to/DHCbatteries.json'; 30 | 31 | //API path: 32 | require($_SERVER['DOCUMENT_ROOT'].'/path/to/phpDevoloAPI.php'); 33 | 34 | $_DHC = new DevoloDHC($login, $password); 35 | if (isset($_DHC->error)) die($_DHC->error); 36 | 37 | ``` 38 | 39 | Don't touch the rest of the file. 40 | 41 | - Call this file everyday. You can use IFTTT, set a sheduled task on NAS, or on cron task on your server or whatever will run the php page. 42 | 43 | ## Display logs 44 | 45 | - Download showLog.html on your server 46 | - Edit showLog.html 47 | 48 | ```html 49 | 50 | 51 | 55 | ``` 56 | 57 | Don't touch the rest of the file. 58 | 59 | - Simply load this page in a browser when you have some logs! 60 | 61 | ## Version history 62 | 63 | #### v0.1 (2017-11-22) 64 | - First public version! 65 | 66 | ## License 67 | 68 | The MIT License (MIT) 69 | 70 | Copyright (c) 2017 KiboOst 71 | 72 | Permission is hereby granted, free of charge, to any person obtaining a copy 73 | of this software and associated documentation files (the "Software"), to deal 74 | in the Software without restriction, including without limitation the rights 75 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 76 | copies of the Software, and to permit persons to whom the Software is 77 | furnished to do so, subject to the following conditions: 78 | 79 | The above copyright notice and this permission notice shall be included in all 80 | copies or substantial portions of the Software. 81 | 82 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 83 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 84 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 85 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 86 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 87 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 88 | SOFTWARE. 89 | -------------------------------------------------------------------------------- /localConnection/README.md: -------------------------------------------------------------------------------- 1 | # php-devoloDHC local 2 | 3 | ## php API for Devolo Home Control 4 | (C) 2017, KiboOst 5 | 6 | The localphpdevoloAPI is a class extending normal phpdevoloAPI. 7 | 8 | It allows you to connect directly to your Devolo Home Control box, without contacting Devolo servers. 9 | 10 | This can be use if you decide to make heavy polling/requests on your box, which I don't encourage, to not flood Devolo servers. 11 | 12 | 13 | ## How-to 14 | - Download class/phpDevoloAPI.php and put it on your server. 15 | - Download localConnection/localphpDevoloAPI.php and put it on your server. 16 | - Include phpDevoloAPI.php and localphpDevoloAPI.php in your script. 17 | 18 | Supported DevoloAPI: v2.21 and up. 19 | 20 | First time execution: 21 | 22 | The API will first request some authorization data from www.mydevolo.com to be able to directly access your Central. 23 | These data won't change for same user, so you can get them and directly pass them next time for complete local connection. 24 | 25 | - Note them in your script or in a config file you include before creating DevoloDHC(). 26 | 27 | - To directly connect to your DHC box, you will need its local IP on your network. You can also put a dyndns address if you have set some NAT/PAT to it. 28 | 29 | ```php 30 | require($_SERVER['DOCUMENT_ROOT']."/path/to/phpDevoloAPI.php"); 31 | require($_SERVER['DOCUMENT_ROOT']."/path/to/localphpDevoloAPI.php"); 32 | 33 | $_DHC = new localDevoloDHC($login, $password, $localHost, null, null, null, false); 34 | if (isset($_DHC->_error)) echo "_DHC error:".$_DHC->_error.'
'; 35 | 36 | $auth = $DHC->getAuth(); 37 | echo "
".json_encode($auth, JSON_PRETTY_PRINT)."

"; 38 | ``` 39 | 40 | Note returned values and next time, call $_DHC = new localDevoloDHC($login, $password, $localHost, $uuid, $gateway, $passkey, false); 41 | 42 | ```php 43 | $DHC = new DevoloDHC($login, $password, $localIP, $uuid, $gateway, $passkey, false); 44 | ``` 45 | 46 | The last *false* argument say to the main API to not try to login on Devolo servers with only your login and password. If you let it to *true*, it will connect normally on Devolo servers but will provide an alternative login to your central if Devolo login fails. 47 | 48 | ## Limitation 49 | 50 | The direct local connection to DHC box has some limitation: 51 | 52 | - Unable to use turnRuleOnOff() 53 | - Unable to use turnTimerOnOff() 54 | 55 | ## License 56 | 57 | The MIT License (MIT) 58 | 59 | Copyright (c) 2017 KiboOst 60 | 61 | Permission is hereby granted, free of charge, to any person obtaining a copy 62 | of this software and associated documentation files (the "Software"), to deal 63 | in the Software without restriction, including without limitation the rights 64 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 65 | copies of the Software, and to permit persons to whom the Software is 66 | furnished to do so, subject to the following conditions: 67 | 68 | The above copyright notice and this permission notice shall be included in all 69 | copies or substantial portions of the Software. 70 | 71 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 72 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 73 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 74 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 75 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 76 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 77 | SOFTWARE. 78 | -------------------------------------------------------------------------------- /ExtendedLogs/DHCconsumptions.json: -------------------------------------------------------------------------------- 1 | { 2 | "21.11.2017": { 3 | "SmartPlug_1": "0.3545kWh", 4 | "SmartPlug_2": "0.4399kWh", 5 | "SmartPlug_3": "1.543kWh", 6 | "SmartPlug_4": "0.4748kWh", 7 | "SmartPlug_5": "0kWh", 8 | "SmartPlug_6": "0.1779kWh", 9 | "SmartPlug_7": "0.0909kWh" 10 | }, 11 | "20.11.2017": { 12 | "SmartPlug_1": "0.298kWh", 13 | "SmartPlug_2": "0.3205kWh", 14 | "SmartPlug_3": "1.2568kWh", 15 | "SmartPlug_4": "1.1778kWh", 16 | "SmartPlug_5": "0.2726kWh", 17 | "SmartPlug_6": "0.1996kWh", 18 | "SmartPlug_7": "0.1959kWh" 19 | }, 20 | "19.11.2017": { 21 | "SmartPlug_1": "0.2492kWh", 22 | "SmartPlug_2": "0.2037kWh", 23 | "SmartPlug_3": "0.8326kWh", 24 | "SmartPlug_4": "1.5411kWh", 25 | "SmartPlug_5": "0.4204kWh", 26 | "SmartPlug_6": "0.1174kWh", 27 | "SmartPlug_7": "0.1782kWh" 28 | }, 29 | "18.11.2017": { 30 | "SmartPlug_1": "0.4172kWh", 31 | "SmartPlug_2": "0.349kWh", 32 | "SmartPlug_3": "1.3839kWh", 33 | "SmartPlug_4": "2.1288kWh", 34 | "SmartPlug_5": "0kWh", 35 | "SmartPlug_6": "0.1054kWh", 36 | "SmartPlug_7": "0.4511kWh" 37 | }, 38 | "17.11.2017": { 39 | "SmartPlug_1": "0.2355kWh", 40 | "SmartPlug_2": "0.3477kWh", 41 | "SmartPlug_3": "2.7693kWh", 42 | "SmartPlug_4": "2.7626kWh", 43 | "SmartPlug_5": "0kWh", 44 | "SmartPlug_6": "0.0681kWh", 45 | "SmartPlug_7": "0.111kWh" 46 | }, 47 | "16.11.2017": { 48 | "SmartPlug_1": "0.5008kWh", 49 | "SmartPlug_2": "0.6419kWh", 50 | "SmartPlug_3": "1.5589kWh", 51 | "SmartPlug_4": "1.3294kWh", 52 | "SmartPlug_5": "0.2514kWh", 53 | "SmartPlug_6": "0.2022kWh", 54 | "SmartPlug_7": "0.4005kWh" 55 | }, 56 | "15.11.2017": { 57 | "SmartPlug_1": "1.9499kWh", 58 | "SmartPlug_2": "0.3031kWh", 59 | "SmartPlug_3": "1.1003kWh", 60 | "SmartPlug_4": "0.4339kWh", 61 | "SmartPlug_5": "0.4047kWh", 62 | "SmartPlug_6": "0.1871kWh", 63 | "SmartPlug_7": "0.1316kWh" 64 | }, 65 | "14.11.2017": { 66 | "SmartPlug_1": "0.8433kWh", 67 | "SmartPlug_2": "0.3204kWh", 68 | "SmartPlug_3": "1.205kWh", 69 | "SmartPlug_4": "2.1333kWh", 70 | "SmartPlug_5": "0.4873kWh", 71 | "SmartPlug_6": "0.112kWh", 72 | "SmartPlug_7": "0.3741kWh" 73 | }, 74 | "13.11.2017": { 75 | "SmartPlug_1": "0.22kWh", 76 | "SmartPlug_2": "0.3348kWh", 77 | "SmartPlug_3": "1.2354kWh", 78 | "SmartPlug_4": "2.1836kWh", 79 | "SmartPlug_5": "0.3379kWh", 80 | "SmartPlug_6": "0.1671kWh", 81 | "SmartPlug_7": "0.4149kWh" 82 | }, 83 | "12.11.2017": { 84 | "SmartPlug_1": "0.4767kWh", 85 | "SmartPlug_2": "0.38kWh", 86 | "SmartPlug_3": "1.5219kWh", 87 | "SmartPlug_4": "2.7468kWh", 88 | "SmartPlug_5": "0.2336kWh", 89 | "SmartPlug_6": "0.0994kWh", 90 | "SmartPlug_7": "0.234kWh" 91 | }, 92 | "11.11.2017": { 93 | "SmartPlug_1": "0.3997kWh", 94 | "SmartPlug_2": "0.4367kWh", 95 | "SmartPlug_3": "1.6488kWh", 96 | "SmartPlug_4": "1.5408kWh", 97 | "SmartPlug_5": "0.4802kWh", 98 | "SmartPlug_6": "0.035kWh", 99 | "SmartPlug_7": "0.3027kWh" 100 | }, 101 | "10.11.2017": { 102 | "SmartPlug_1": "0.2651kWh", 103 | "SmartPlug_2": "0.5417kWh", 104 | "SmartPlug_3": "1.8924kWh", 105 | "SmartPlug_4": "1.7683kWh", 106 | "SmartPlug_5": "0.1038kWh", 107 | "SmartPlug_6": "0.1262kWh", 108 | "SmartPlug_7": "0.4535kWh" 109 | }, 110 | "09.11.2017": { 111 | "SmartPlug_1": "0.3868kWh", 112 | "SmartPlug_2": "0.3242kWh", 113 | "SmartPlug_3": "1.2304kWh", 114 | "SmartPlug_4": "1.0625kWh", 115 | "SmartPlug_5": "0.5511kWh", 116 | "SmartPlug_6": "0.1761kWh", 117 | "SmartPlug_7": "0.5198kWh" 118 | }, 119 | "08.11.2017": { 120 | "SmartPlug_1": "0.1929kWh", 121 | "SmartPlug_2": "0.3254kWh", 122 | "SmartPlug_3": "1.1659kWh", 123 | "SmartPlug_4": "0kWh", 124 | "SmartPlug_5": "0.3389kWh", 125 | "SmartPlug_6": "0.1785kWh", 126 | "SmartPlug_7": "0.7211kWh" 127 | }, 128 | "07.11.2017": { 129 | "SmartPlug_1": "0.4558kWh", 130 | "SmartPlug_2": "0.3241kWh", 131 | "SmartPlug_3": "1.1234kWh", 132 | "SmartPlug_4": "1.43kWh", 133 | "SmartPlug_5": "0.3824kWh", 134 | "SmartPlug_6": "0.1671kWh", 135 | "SmartPlug_7": "0.3877kWh" 136 | }, 137 | "06.11.2017": { 138 | "SmartPlug_1": "0.4461kWh", 139 | "SmartPlug_2": "0.3348kWh", 140 | "SmartPlug_3": "1.1519kWh", 141 | "SmartPlug_4": "1.4767kWh", 142 | "SmartPlug_5": "0.216kWh", 143 | "SmartPlug_6": "0.1338kWh", 144 | "SmartPlug_7": "0.3299kWh" 145 | } 146 | } -------------------------------------------------------------------------------- /ExtendedLogs/showLog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | Devolo reports 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 33 | 34 | 35 | 36 |
37 |
38 |
39 |
40 |
41 |
42 | 43 |
44 |
45 |
46 |
47 |
48 |
49 | 50 | 111 | 112 | 183 | 184 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /localConnection/localphpdevoloAPI.php: -------------------------------------------------------------------------------- 1 | _login = $login; 25 | $this->_password = $password; 26 | $this->_localHost = $localHost; 27 | 28 | if (isset($uuid)) $this->_uuid = $uuid; 29 | if (isset($gateway)) $this->_gateway = $gateway; 30 | if (isset($passkey)) $this->_passkey = $passkey; 31 | 32 | parent::__construct($login, $password, $connect, $gateIdx); //construct main devoloAPI 33 | 34 | if ( isset($this->error) or ($connect==false) ) 35 | { 36 | if ( isset($this->error) ) echo 'DevoloDHC class error:'.$this->error.'
'; 37 | 38 | //use alternative login 39 | $this->_dhcUrl = $this->_localHost; 40 | if ( !isset($this->_uuid) or !isset($this->_gateway) or !isset($this->_passkey) ) 41 | { 42 | //get uuid, gateway and passkey from Devolo server: 43 | $this->initAuth(); 44 | } 45 | //connect directly to the central: 46 | $this->getSessionID(); 47 | $this->getDevices(); 48 | } 49 | } 50 | 51 | public function getAuth() //return array of infos for faster connections with all datas 52 | { 53 | $auth = array( 54 | "uuid" => $this->_uuid, 55 | "gateway" => $this->_gateway, 56 | "passkey" => $this->_passkey, 57 | "call" => 'new localDevoloDHC($login, $password, $localHost, $uuid, $gateway, $passkey, false)' 58 | ); 59 | return array('result'=>$auth); 60 | } 61 | 62 | protected function _MyRequest($protocol, $method, $host, $path, $jsonString, $login, $password) //standard function handling all get/post request with curl | return string 63 | { 64 | if (!isset($this->_curlHdl)) 65 | { 66 | $this->_curlHdl = curl_init(); 67 | curl_setopt($this->_curlHdl, CURLOPT_RETURNTRANSFER, true); 68 | curl_setopt($this->_curlHdl, CURLOPT_FOLLOWLOCATION, true); 69 | 70 | curl_setopt($this->_curlHdl, CURLOPT_COOKIESESSION, false); 71 | 72 | curl_setopt($this->_curlHdl, CURLOPT_COOKIEJAR, ''); 73 | curl_setopt($this->_curlHdl, CURLOPT_COOKIEFILE, ''); 74 | 75 | curl_setopt($this->_curlHdl, CURLOPT_REFERER, 'http://www.google.com/'); 76 | curl_setopt($this->_curlHdl, CURLOPT_USERAGENT, 'Mozilla/5.0+(Windows;+WOW64;+x64;+rv:52.0)+Gecko/20100101+Firefox/52.0'); 77 | 78 | curl_setopt($this->_curlHdl, CURLOPT_SSL_VERIFYPEER, false); 79 | curl_setopt($this->_curlHdl, CURLOPT_SSL_VERIFYHOST, false); 80 | curl_setopt($this->_curlHdl, CURLOPT_HTTPHEADER, array('Content-Type: application/xml')); 81 | curl_setopt($this->_curlHdl,CURLOPT_ENCODING , ''); 82 | } 83 | $url = $protocol."://".$host.$path; 84 | curl_setopt($this->_curlHdl, CURLOPT_URL, $url); 85 | 86 | if ($protocol == 'http') 87 | { 88 | curl_setopt($this->_curlHdl, CURLOPT_HEADER, true); 89 | curl_setopt($this->_curlHdl, CURLINFO_HEADER_OUT, true ); 90 | } 91 | 92 | if ( isset($login) and isset($password) ) 93 | { 94 | $auth = urldecode($login).":".urldecode($password); 95 | curl_setopt($this->_curlHdl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 96 | curl_setopt($this->_curlHdl, CURLOPT_USERPWD, $auth); 97 | } 98 | 99 | if ($method == 'POST') 100 | { 101 | $jsonString = str_replace('"jsonrpc":"2.0",', '"jsonrpc":"2.0", "id":'.$this->_POSTid.',', $jsonString); 102 | $this->_POSTid++; 103 | curl_setopt($this->_curlHdl, CURLOPT_CUSTOMREQUEST, 'POST'); 104 | curl_setopt($this->_curlHdl, CURLOPT_POSTFIELDS, $jsonString); 105 | } 106 | 107 | $response = curl_exec($this->_curlHdl); 108 | 109 | //$info = curl_getinfo($this->_curlHdl); 110 | //echo "
cURL info".json_encode($info, JSON_PRETTY_PRINT)."

"; 111 | 112 | if($response === false) 113 | { 114 | echo 'cURL error: ' . curl_error($this->_curlHdl); 115 | } 116 | else 117 | { 118 | return $response; 119 | } 120 | } 121 | 122 | public function initAuth() //get uuid, gateway and passkey from www.devolo.com for authorization 123 | { 124 | //get uuid: 125 | $data = $this->_MyRequest('https', 'GET', $this->_Host, $this->_apiVersion.'/users/uuid', null, $this->_login, $this->_password, null); 126 | $data = json_decode($data, true); 127 | if (isset($data["uuid"])) 128 | { 129 | $this->_uuid = $data["uuid"]; 130 | } 131 | else 132 | { 133 | $this->_error = "Couldn't find Devolo uuid."; 134 | return false; 135 | } 136 | 137 | //get gateway: 138 | $path = $this->_apiVersion.'/users/'.$this->_uuid.'/hc/gateways'; 139 | $data = $this->_MyRequest('https', 'GET', $this->_Host, $path, null, $this->_login, $this->_password, null); 140 | $data = json_decode($data, true); 141 | if (isset($data["items"][0]["href"])) 142 | { 143 | $var = explode( "/gateways/", $data["items"][0]["href"] ); 144 | $this->_gateway = $var[1]; 145 | } 146 | else 147 | { 148 | $this->_error = "Couldn't find Devolo gateway."; 149 | return false; 150 | } 151 | 152 | 153 | //get localPasskey: 154 | $path = $this->_apiVersion.'/users/'.$this->_uuid.'/hc/gateways/'.$this->_gateway; 155 | $data = $this->_MyRequest('https', 'GET', $this->_Host, $path, null, $this->_login, $this->_password, null); 156 | $data = json_decode($data, true); 157 | if (isset($data["localPasskey"])) 158 | { 159 | $this->_passkey = $data["localPasskey"]; 160 | if ($data["state"] != 'devolo.hc_gateway.state.idle') 161 | { 162 | $this->error = "Devolo Central not IDLE."; 163 | return false; 164 | } 165 | } 166 | else 167 | { 168 | $this->_error = "Couldn't find Devolo localPasskey."; 169 | return false; 170 | } 171 | 172 | return true; 173 | } 174 | 175 | public function getSessionID() //get and set cookie for later authorized requests 176 | { 177 | $this->_sessionID = null; 178 | 179 | //get token: 180 | $data = $this->_MyRequest('http', 'GET', $this->_dhcUrl, '/dhlp/portal/light', null, $this->_uuid, $this->_passkey, null); 181 | $var = explode('?token=', $data); 182 | if(count($var)>1) 183 | { 184 | $var = explode('","', $var[1]); 185 | $token = $var[0]; 186 | } 187 | else 188 | { 189 | $this->_error = "Couldn't find Devolo Central Token in response request."; 190 | return false; 191 | } 192 | 193 | $path = '/dhlp/portal/light/?token='.$token; 194 | $data = $this->_MyRequest('http', 'GET', $this->_dhcUrl, $path, null, $this->_uuid, $this->_passkey, null); 195 | $var = explode("JSESSIONID=", $data); 196 | if(count($var)>1) 197 | { 198 | $var = explode("; ", $var[1]); 199 | $this->_sessionID = $var[0]; 200 | } 201 | else 202 | { 203 | $this->_error = "Couldn't find sessionID from response request."; 204 | return false; 205 | } 206 | return true; 207 | } 208 | 209 | //localDevoloDHC end 210 | } 211 | 212 | ?> 213 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # php-devoloDHC 4 | 5 | ## php API for Devolo Home Control 6 | 7 | This php API allows you to control your Devolo Home Control devices. 8 | The following devices are currently supported: 9 | 10 | - Devolo Smart Metering Plug (get/set) 11 | - Devolo Wall Switch / Devolo Key Fob (get/set) 12 | - Devolo Siren (get/set) 13 | - Devolo Room Thermostat / Radiator Thermostat(valve) (get/set) 14 | - Devolo Flood Sensor (get) 15 | - Devolo Humidity Sensor (get) 16 | - Devolo Motion Sensor (get) 17 | - Devolo Door/Window Contact (get) 18 | - http devices (get/set)

19 | - Scenes (get/set) 20 | - Groups (get/set) 21 | - Timers (get/set) 22 | - Rules (get/set) 23 | - Messages (get/set)

24 | - Qubino "Flush Shutter" ZMNHCD1 (get/set) 25 | - Qubino "Flush 1D Relay" ZMNHND1 (get/set) 26 | - Qubino "Flush 2 Relay" ZMNHBD1 (get/set one or both contacts) 27 | - Qubino "Flush Dimmer" ZMNHDD1 (get/set/dim)

28 | - Busch-Jaeger Duro 2000 - ZME_05461 (get/set) 29 | 30 | Changing settings will appear in Devolo web interface / Apps daily diary with your account as usual. 31 | 32 | Feel free to submit an issue or pull request to add more. 33 | 34 | Need a python version of this API ? [python-devoloDHC](https://github.com/KiboOst/python-devoloDHC) 35 | 36 | *This isn't an official API | USE AT YOUR OWN RISK!
37 | Anyway this API use exact same commands as your Devolo Home Control, which is based on ProSyst mBS SDK. When you ask bad stuff to the central, this one doesn't burn but just answer this isn't possible or allowed.
38 | This API is reverse-engineered, provided for research and development for interoperability.* 39 | 40 | --- 41 | :exclamation: **WARNING** :exclamation: 42 | 43 | I'm sorry to say that I have switch to Jeedom and do not use anymore Devolo Home Control solution. 44 | This API has work flawlessly since it's creation here, but in case of coming problems I won't be able to fix or extend it anymore. 45 | 46 | If someone want to continue further development of this API, contact me. 47 | 48 | --- 49 | 50 | [Requirements](#requirements)
51 | [How-to](#how-to)
52 | [Connection](#connection)
53 | [Reading datas](#reading-operations)
54 | [Changing datas](#changing-operations)
55 | [Consumption](#consumption)
56 | [Unsupported device](#unsupported-device)
57 | [Version history](#version-history)
58 | 59 | 60 | 61 | ## Requirements 62 | - PHP v5+ 63 | - cURL (quite standard in PHP servers). 64 | - The API require internet access (it will authenticate against Devolo servers). 65 | 66 | [⇑](#php-devolodhc) 67 | 68 | 69 | ## How-to 70 | - Download class/phpDevoloAPI.php and put it on your server. 71 | - If you can, allow write permission for the API folder. It will support keeping DHC user session between consecutive executions of your script (also lot faster). 72 | - Include phpDevoloAPI.php in your script. 73 | - Start it with your Devolo username/password. 74 | 75 | #### Connection 76 | 77 | ```php 78 | require($_SERVER['DOCUMENT_ROOT'].'/path/to/phpDevoloAPI.php'); 79 | $DHC = new DevoloDHC($login, $password); 80 | if (isset($DHC->error)) echo $DHC->error; 81 | ``` 82 | 83 | If you have several Central Units, or keep the demo central on your *mydevolo* page, you can choose which to connect to: 84 | 85 | ```php 86 | //(login | password | connect or not, default true | which central, default 0) 87 | $DHC = new DevoloDHC($login, $password, true, 1); 88 | if (isset($DHC->error)) echo $DHC->error; 89 | ``` 90 | 91 | Let the fun begin: 92 | 93 | ```php 94 | //get some infos on your Devolo Home Control box: 95 | echo "__infos__
"; 96 | $infos = $DHC->getInfos(); 97 | echo "
".json_encode($infos['result'], JSON_PRETTY_PRINT)."

"; 98 | ``` 99 | [⇑](#php-devolodhc) 100 | 101 | 102 | #### READING OPERATIONS
103 | *Change devices names by yours!* 104 | 105 | ```php 106 | //get all devices in a zone: 107 | $zone = $DHC->getDevicesByZone('living room'); 108 | echo "
zone:
".json_encode($zone, JSON_PRETTY_PRINT)."

"; 109 | 110 | //get rule or timer state: 111 | $state = $DHC->isRuleActive('MyRule'); 112 | echo "Rule state:".$state['result']."
"; 113 | $state = $DHC->isTimerActive('MyTimer'); 114 | echo "Timer state:".$state['result']."
"; 115 | 116 | //Check if a device is on (0=off, 1=on) 117 | $state = $DHC->isDeviceOn('My Wall Plug'); 118 | echo "Device state:".$state['result']."
"; 119 | 120 | //Check for devices with 2 relays (eg. Qubino Flush 2 Relay ZMNHBD1) is on (0=off, 1=on) 121 | //contact 1 122 | $state = $DHC->isDeviceOn('myRelay', 1); 123 | echo "Device state:".$state['result']."
"; 124 | //contact 2 125 | $state = $DHC->isDeviceOn('myRelay', 2); 126 | echo "Device state:".$state['result']."
"; 127 | //all contacts 128 | $state = $DHC->isDeviceOn('myRelay', 'all'); 129 | echo "Device state:".$state['result']."
"; 130 | 131 | //check a device battery level: 132 | $batteryLevel = $DHC->getDeviceBattery('My Motion Sensor'); 133 | echo "BatteryLevel:".$batteryLevel['result']."
"; 134 | 135 | //get all batteries level under 20% (ommit argument to have all batteries levels): 136 | $BatLevels = $DHC->getAllBatteries(20); 137 | echo "
Batteries Levels:
".json_encode($BatLevels['result'], JSON_PRETTY_PRINT)."

"; 138 | 139 | //get daily diary, last number of events: 140 | $diary = $DHC->getDailyDiary(10); 141 | echo "
diary:
".json_encode($diary['result'], JSON_PRETTY_PRINT)."

"; 142 | 143 | //get daily device stat: 144 | //0:today, 1:yesterday, 2:day before yesterday 145 | $stats = $DHC->getDailyStat('My MotionSensor', 0) 146 | 147 | //get weather report: 148 | $weather = $DHC->getWeather() 149 | echo "
weather:
".json_encode($weather, JSON_PRETTY_PRINT)."

"; 150 | 151 | //Get one device states (all sensors): 152 | $states = $DHC->getDeviceStates('My Motion Sensor'); 153 | echo "
States: My Siren:".json_encode($states, JSON_PRETTY_PRINT)."

"; 154 | 155 | //Get one sensor data for any device, like light from a Motion Sensor or energy from a Wall Plug: 156 | $data = $DHC->getDeviceData('My Motion Sensor', 'light'); 157 | echo "MyMotionSensor luminosity: ".$data['result']['value']."
"; 158 | $data = $_DHC->getDeviceData('Radiator', 'temperature'); 159 | echo $data['result']['value']; 160 | 161 | //You can first ask without data, it will return all available sensors datas for this device: 162 | $data = $DHC->getDeviceData('My Wall Plug'); 163 | echo "
MyWallPlug available states:
".json_encode($data, JSON_PRETTY_PRINT)."

"; 164 | 165 | //get url from http device: 166 | $url = $DHC->getDeviceURL('myhttp device'); 167 | 168 | //get message data: 169 | $url = $DHC->getMessageData('MyAlert'); 170 | ``` 171 | 172 | [⇑](#php-devolodhc) 173 | 174 | 175 | #### CHANGING OPERATIONS
176 | *Change devices names by yours!* 177 | 178 | ```php 179 | //TURN DEVICE ON(1) or OFF(0): 180 | //supported: all on/off devices and http devices 181 | $DHC->turnDeviceOnOff("My Room wallPlug", 1); 182 | 183 | //for devices with 2 relays as Qubino Flush 2 Relay ZMNHBD1 (device name, state, contact): 184 | //contact 1 on 185 | $DHC->turnDeviceOnOff('myRelay', 1, 1); 186 | //contact 2 on 187 | $DHC->turnDeviceOnOff('myRelay', 1, 2); 188 | //all contacts on 189 | $DHC->turnDeviceOnOff('myRelay', 1, 'All'); 190 | 191 | //TURN GROUP ON(1) or OFF(0): 192 | $DHC->turnGroupOnOff('My Plugs Group', 1); 193 | 194 | //RUN HTTP DEVICE: 195 | $DHC->turnDeviceOnOff('My http device', 1); //, 0 won't do anything of course. 196 | 197 | //START SCENE: 198 | $DHC->startScene('We go out'); 199 | 200 | //SEND MESSAGE: 201 | $DHC->sendMessage('Alert'); 202 | 203 | //CHANGE THERMOSTAT/VALVE VALUE: 204 | $targetValue = $DHC->setDeviceValue('My radiator', 21); 205 | echo "
".json_encode($targetValue['result'], JSON_PRETTY_PRINT)."

"; 206 | $_DHC->setDeviceValue('my thermostat', 19); 207 | //press thermostat button: 208 | $_DHC->pressDeviceKey('my thermostat', 1); 209 | 210 | //TURN SIREN ON: (last number is the indice of the tone in the interface list. For example, 1 is alarm and won't stop! 0 will!) 211 | $DHC->setDeviceValue('My Devolo Siren', 5); 212 | 213 | //SET SHUTTER OPENING: 214 | $DHC->setDeviceValue('qubShutter', 50); 215 | 216 | //SET DIMMER VALUE: 217 | $DHC->setDeviceValue('qubDimmer', 50); 218 | 219 | //PRESS REMOTE SWITCH KEY OR KEY FOB KEY: 220 | $DHC->pressDeviceKey('MySwitch', 3); 221 | 222 | //TURN RULE ACTIVE (1 or 0) 223 | $DHC->turnRuleOnOff('MyRule', 1); 224 | 225 | //TURN TIMER ACTIVE (1 or 0) 226 | $DHC->turnTimerOnOff('MyTimer', 1); 227 | 228 | //TURN OFF DAILY DIARY REPORT (true/false): 229 | $DHC->setDeviceDiary('movekitchen', false); 230 | ``` 231 | 232 | [⇑](#php-devolodhc) 233 | 234 | 235 | #### Consumption 236 | 237 | Some people would like to have more than 3days consumption log for devices like Wall Plugs. 238 | Here are two functions to log consumptions, and read them between two dates of choice. So you can make a cron task to call this function everyday, it will log the yesterday total consumption of each Wall Plugs: 239 | 240 | ```php 241 | $DHC->logConsumption('log.json'); 242 | ``` 243 | If you don't provide a file path, or it can't write to, the api will return an error, but also provide the result (so you can write your own custom functions).
244 | Then, to read the log and know consumption for a month, or along summer/winter etc: 245 | 246 | ```php 247 | $stats = $DHC->getLogConsumption('log.json', '01.03.2017', '31.03.2017'); 248 | echo "
".json_encode($stats, JSON_PRETTY_PRINT)."

"; 249 | ``` 250 | Of course, it needs a valid previously saved log file by the api. You can provide no dates (full log), or only one (set first as null if needed). Just respect day.month.year (php 'd.m.Y'). 251 | 252 | For visual logs feedback, have a look [here](ExtendedLogs) 253 | 254 |

255 | 256 | [⇑](#php-devolodhc) 257 | #### Unsupported device 258 | 259 | If you have unsupported device, you can call special function with this device and post the return in a new issue. 260 | 261 | [Request for unsupported device](../../issues/) 262 | 263 | ```php 264 | $help = $DHC->debugDevice('MyStrangeDevice'); 265 | ``` 266 | [⇑](#php-devolodhc) 267 | 268 | 269 | ## Version history 270 | 271 | #### v 2.80 (2017-09-23) 272 | - New: getNumStats() report number of devices, rules, timers, scenes, groups, zones, messages 273 | - Enhanced: Qubino Flush 2 Relay ZMNHBD1 support
274 | $_DHC->turnDeviceOnOff('my2relay', 1, 'All') //support 1, 2, 'All' for Q1, Q2, both
275 | $_DHC->isDeviceOn('my2relay', 1) //support 1, 2, 'All' for Q1, Q2, both 276 | 277 | #### v 2.72 (2017-06-02) 278 | - New: support for last Devolo update: setDeviceDiary('devicename', true) 279 | - New: qubino/devolo shutter flush module support 280 | 281 | *qubino/devolo 1 relay and dimmer should works also* 282 | 283 | #### v 2.6 (2017-04-05) 284 | - New: getAllZones() / getAllGroups() / getAllRules() / getAllTimers() / getAllScenes() / getAllMessages() 285 | - Change: logConsumption() now sort result with recent dates up. 286 | 287 | #### v 2.55 (2017-03-30) 288 | - New: getWeather() 289 | - Change: faster getInfos()
290 | *Development should now slow down as we have it all. Keeping an eye on issues and requests of course!* 291 | 292 | #### v 2.5 (2017-03-29) 293 | - New: Session preservation for consecutive executions. 294 | 295 | #### v 2.3 (2017-03-27) 296 | - New: Messages support (getMessageData, sendMessage) 297 | 298 | #### v 2.2 (2017-03-22) 299 | - Minor bugfixs 300 | - Faster, more robust starting 301 | 302 | #### v 2.0 (2017-03-18) 303 | - All new authentication method with only your Devolo username and password! No more passkey, localIP etc. 304 | - Faster! 305 | - turnRuleOnOff() 306 | - turnTimerOnOff() 307 | 308 | #### v 1.2 (2017-03-14) 309 | - New: turnGroupOnOff() / Feature requested by API user. 310 | 311 | #### v 1.1 (2017-03-13) 312 | - New: getDailyStat() 313 | - New: logConsumption() and getLogConsumption() 314 | - More error handling in provided arguments 315 | 316 | #### v 1.0 (2017-03-12) 317 | - Changed: For convenience, all functions now return an array with datas in array['result']. 318 | If there is an error, message is in array['error'] and result is null. So you can easily check for error first. 319 | - Fix: $DHC->setDeviceValue('MyDevoloSiren', 1) now works (1 is the indice of the tone in the interface list). 320 | - Fix: Lot more error handling. 321 | 322 | [⇑](#php-devolodhc) 323 | 324 | 325 | ## License 326 | 327 | The MIT License (MIT) 328 | 329 | Copyright (c) 2017 KiboOst 330 | 331 | Permission is hereby granted, free of charge, to any person obtaining a copy 332 | of this software and associated documentation files (the "Software"), to deal 333 | in the Software without restriction, including without limitation the rights 334 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 335 | copies of the Software, and to permit persons to whom the Software is 336 | furnished to do so, subject to the following conditions: 337 | 338 | The above copyright notice and this permission notice shall be included in all 339 | copies or substantial portions of the Software. 340 | 341 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 342 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 343 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 344 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 345 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 346 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 347 | SOFTWARE. 348 | -------------------------------------------------------------------------------- /dev/phpDevoloAPI.php: -------------------------------------------------------------------------------- 1 | getHueHSB('myHue') 8 | $_DHC->getHueRGB('myHue') 9 | $_DHC->setHueRGB('myHue', array(128, 128, 128)) 10 | $_DHC->turnDeviceOnOff('myHue', 1) 11 | */ 12 | 13 | class DevoloDHC{ 14 | 15 | public $_version = '2.7dev'; 16 | //user functions====================================================== 17 | public function getInfos() //return infos from this api, Devolo user, and Devolo central 18 | { 19 | 20 | if (!isset($this->_userInfos)) 21 | { 22 | //get uuid: 23 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItemUIDs","params":["(objectClass=com.devolo.fi.page.Dashboard)"]}'; 24 | $answer = $this->sendCommand($jsonString); 25 | $uuid = $answer['result'][0]; 26 | $uuid = explode('devolo.Dashboard.', $uuid)[1]; 27 | $this->_uuid = $uuid; 28 | 29 | //get user infos: 30 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItems","params":[["devolo.UserPrefs.'.$this->_uuid.'"],0]}'; 31 | $answer = $this->sendCommand($jsonString); 32 | $this->_userInfos = $answer['result']['items'][0]['properties']; 33 | } 34 | 35 | if (!isset($this->_centralInfos)) 36 | { 37 | //get portal manager token 38 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItemUIDs","params":["(objectClass=com.devolo.fi.gw.PortalManager)"]}'; 39 | $answer = $this->sendCommand($jsonString); 40 | if ( isset($answer['result'][0]) ) 41 | { 42 | $var = $answer['result'][0]; 43 | $this->_token = str_replace('devolo.mprm.gw.PortalManager.', '', $var); 44 | } 45 | else return array('error'=>'Could not find info token.'); 46 | 47 | //get central infos: 48 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItems","params":[["devolo.mprm.gw.PortalManager.'.$this->_token.'"],0]}'; 49 | $answer = $this->sendCommand($jsonString); 50 | 51 | $centralInfos = 'None'; 52 | if ( isset($answer['result']['items'][0]['properties']) ) 53 | { 54 | $this->_centralInfos = $answer['result']['items'][0]['properties']; 55 | $this->_gateway = $this->_centralInfos['gateway']; 56 | } 57 | } 58 | 59 | $infos = array( 60 | 'phpAPI version' => $this->_version, 61 | 'user' => $this->_userInfos, 62 | 'central' => $this->_centralInfos 63 | ); 64 | return array('result'=>$infos); 65 | } 66 | 67 | //IS: 68 | public function isRuleActive($rule) 69 | { 70 | if ( is_string($rule) ) $rule = $this->getRuleByName($rule); 71 | if ( isset($rule['error']) ) return $rule; 72 | 73 | $answer = $this->fetchItems(array($rule['element'])); 74 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 75 | $state = $answer['result']['items'][0]['properties']['enabled']; 76 | $state = ($state > 0 ? 'active' : 'inactive'); 77 | return array('result'=>$state); 78 | } 79 | 80 | public function isTimerActive($timer) 81 | { 82 | if ( is_string($timer) ) $timer = $this->getTimerByName($timer); 83 | if ( isset($timer['error']) ) return $timer; 84 | 85 | return $this->isRuleActive($timer); 86 | } 87 | 88 | public function isDeviceOn($device) //return true of false if find a sensor state in device 89 | { 90 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 91 | if ( isset($device['error']) ) return $device; 92 | 93 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true): null); 94 | if ($sensors == null) return array('result'=>null, 'error' => 'Unfound sensor for device'); 95 | 96 | foreach ($sensors as $sensor) 97 | { 98 | $sensorType = $this->getSensorType($sensor); 99 | 100 | if (in_array($sensorType, $this->_SensorsOnOff)) 101 | { 102 | $answer = $this->fetchItems(array($sensor)); 103 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 104 | if ( isset($answer['result']['items'][0]['properties']['state']) ) 105 | { 106 | $state = $answer['result']['items'][0]['properties']['state']; 107 | $isOn = ($state > 0 ? 'on' : 'off'); 108 | return array('result' => $isOn); 109 | } 110 | $param = $this->getValuesByType($sensorType); 111 | } 112 | } 113 | return array('result'=>null, 'error' => 'Unfound OnOff sensor for device'); 114 | } 115 | 116 | //GET: 117 | public function getDeviceStates($device, $DebugReport=null) //return array of sensor type and state 118 | { 119 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 120 | if ( isset($device['error']) ) return $device; 121 | 122 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true) : null); 123 | if ($sensors == null) return array('result'=>null, 'error' => 'Unfound device'); 124 | 125 | //fetch sensors: 126 | $arrayStates = array(); 127 | 128 | foreach($sensors as $sensor) 129 | { 130 | $sensorType = $this->getSensorType($sensor); 131 | $param = $this->getValuesByType($sensorType); 132 | if ($param != null) 133 | { 134 | $answer = $this->fetchItems(array($sensor)); 135 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 136 | if ($DebugReport == true) echo '
'.json_encode($answer, JSON_PRETTY_PRINT).'

'; 137 | $jsonSensor = array('sensorType' => $sensorType); 138 | foreach ($param as $key) 139 | { 140 | $value = $answer['result']['items'][0]['properties'][$key]; 141 | //Seems Devolo doesn't know all about its own motion sensor... 142 | if ($key=='sensorType' and $value=='unknown') continue; 143 | //echo 'sensorType:'.$sensorType.', key:'.$key.', value:'.$value.'
'; 144 | $value = $this->formatStates($sensorType, $key, $value); 145 | $jsonSensor[$key] = $value; 146 | } 147 | $arrayStates[] = $jsonSensor; 148 | } 149 | elseif ( !in_array($sensorType, $this->_SensorsNoValues) ) //Unknown, unsupported sensor! 150 | { 151 | $answer = $this->fetchItems(array($sensor)); 152 | echo "DEBUG - UNKNOWN PARAM - Please help and report this message on https://github.com/KiboOst/php-devoloDHC or email it to ".base64_decode('a2lib29zdEBmcmVlLmZy')."
"; 153 | echo '
infos:'.json_encode($answer, JSON_PRETTY_PRINT).'

'; 154 | } 155 | } 156 | return array('result'=>$arrayStates); 157 | } 158 | 159 | public function getDeviceData($device, $askData=null) //get device sensor data. If not asked data, return available datas 160 | { 161 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 162 | if ( isset($device['error']) ) return $device; 163 | 164 | $datas = $this->getDeviceStates($device); 165 | $availableDatas = array(); 166 | foreach ($datas['result'] as $item) 167 | { 168 | array_push($availableDatas, $item['sensorType']); 169 | @array_push($availableDatas, $item['switchType']); 170 | if ($item['sensorType'] == $askData or @$item['switchType'] == $askData) return array('result'=>$item); 171 | } 172 | $error = array('result'=>null, 173 | 'error' => 'Unfound data for this Device', 174 | 'available' => $availableDatas 175 | ); 176 | return $error; 177 | } 178 | 179 | public function getDevicesByZone($zoneName) 180 | { 181 | foreach($this->_AllZones as $thisZone) 182 | { 183 | if ($thisZone['name'] == $zoneName) 184 | { 185 | $devicesUIDS = $thisZone['deviceUIDs']; 186 | $jsonArray = array(); 187 | foreach ($this->_AllDevices as $thisDevice) 188 | { 189 | if (in_array($thisDevice['uid'], $devicesUIDS)) $jsonArray[] = $thisDevice; 190 | } 191 | return array('result'=>$jsonArray); 192 | } 193 | } 194 | return array('result'=>null, 'error'=>'Unfound '.$zoneName); 195 | } 196 | 197 | public function getDeviceURL($device) 198 | { 199 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 200 | if ( isset($device['error']) ) return $device; 201 | 202 | $uid = $device['uid']; 203 | if (!stristr($uid, 'hdm:DevoloHttp:virtual')) return array('result'=>null, 'error' => 'This is not an http virtual device'); 204 | 205 | $hdm = str_replace('hdm:DevoloHttp:virtual', 'hs.hdm:DevoloHttp:virtual', $uid); 206 | $answer = $this->fetchItems(array($hdm)); 207 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 208 | $url = $answer['result']['items'][0]['properties']['httpSettings']['request']; 209 | return array('result'=>$url); 210 | } 211 | 212 | public function getDeviceBattery($device) 213 | { 214 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 215 | if ( isset($device['error']) ) return $device; 216 | 217 | $batLevel = $device['batteryLevel']; 218 | if ($batLevel == 'None' or $batLevel == -1) $batLevel = 'No battery'; 219 | 220 | return array('result'=>$batLevel); 221 | } 222 | 223 | public function getAllBatteries($lowLevel=100, $filter=1) 224 | { 225 | $jsonDatas = array(); 226 | $c = count($this->_AllDevices); 227 | foreach ($this->_AllDevices as $thisDevice) 228 | { 229 | $thisDeviceName = $thisDevice['name'] ; 230 | $thisBatLevel = $thisDevice['batteryLevel']; 231 | if (($thisBatLevel == -1) or ($thisBatLevel == 'None')) {if ($filter==1) continue; } 232 | 233 | $datas = array('name' => $thisDeviceName, 'battery_percent' => $thisBatLevel); 234 | if ($thisBatLevel <= $lowLevel) array_push($jsonDatas, $datas); 235 | } 236 | return array('result'=>$jsonDatas); 237 | } 238 | 239 | public function getDailyDiary($numEvents=20) 240 | { 241 | if (!is_int($numEvents)) return array('error'=> 'Provide numeric argument as number of events to report'); 242 | if ($numEvents < 0) return array('error'=> 'Dude, what should I report as negative number of events ? Are you in the future ?'); 243 | 244 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/invokeOperation","params":["devolo.DeviceEvents","retrieveDailyData",[0,0,'.$numEvents.']]}'; 245 | $answer = $this->sendCommand($jsonString); 246 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 247 | 248 | $jsonDatas = array(); 249 | $numEvents = count($answer['result'])-1; //may have less than requested 250 | foreach (array_reverse($answer['result']) as $event) 251 | { 252 | $deviceName = $event['deviceName']; 253 | $deviceZone = $event['deviceZone']; 254 | $author = $event['author']; 255 | $timeOfDay = $event['timeOfDay']; 256 | $timeOfDay = gmdate('H:i:s', $timeOfDay); 257 | 258 | $datas = array( 259 | 'deviceName' => $deviceName, 260 | 'deviceZone' => $deviceZone, 261 | 'author' => $author, 262 | 'timeOfDay' => $timeOfDay 263 | ); 264 | $jsonDatas[] = $datas; 265 | } 266 | return array('result'=>$jsonDatas); 267 | } 268 | 269 | public function getDailyStat($device, $dayBefore=0) 270 | { 271 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 272 | if ( isset($device['error']) ) return $device; 273 | 274 | if (!is_int($dayBefore)) return array('error'=> 'second argument should be 0 1 or 2 for today, yesterday, day before yesterday'); 275 | 276 | $operation = "retrieveDailyStatistics"; 277 | $statSensor = $device['statUID']; 278 | if ($statSensor=='None') return array('result'=>null, 'error'=>"No statistic for such device."); 279 | $answer = $this->invokeOperation($statSensor, $operation, $dayBefore); 280 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 281 | 282 | $jsonDatas = array(); 283 | foreach ($answer['result'] as $item) 284 | { 285 | $sensor = $item['widgetElementUID']; 286 | $values = $item['value']; 287 | if ( isset($item['timeOfDay']) ) $timesOfDay = $item['timeOfDay']; 288 | 289 | if (strstr($device['model'], 'Door/Window:Sensor')) 290 | { 291 | if (strstr($sensor, 'BinarySensor:hdm')) $sensor = 'opened'; 292 | if (strstr($sensor, '#MultilevelSensor(1)')) $sensor = 'temperature'; 293 | if (strstr($sensor, '#MultilevelSensor(3)')) $sensor = 'light'; 294 | } 295 | if (strstr($device['model'], 'Motion:Sensor')) 296 | { 297 | if (strstr($sensor, 'BinarySensor:hdm')) $sensor = 'alarm'; 298 | if (strstr($sensor, '#MultilevelSensor(1)')) $sensor = 'temperature'; 299 | if (strstr($sensor, '#MultilevelSensor(3)')) $sensor = 'light'; 300 | } 301 | if (strstr($device['model'], 'Wall:Plug:Switch:and:Meter')) 302 | { 303 | if (strstr($sensor, 'Meter:hdm')) $sensor = 'consumption'; 304 | } 305 | 306 | $sensorData = array('sensor'=>$sensor); 307 | $countValues = count($values)-1; 308 | for($i=$countValues; $i>=1; $i--) 309 | { 310 | $timeOfDay = gmdate("H:i:s", $timesOfDay[$i]); 311 | $sensorData[$timeOfDay] = $values[$i]; 312 | } 313 | $jsonDatas[] = $sensorData; 314 | } 315 | return array('result'=>$jsonDatas); 316 | } 317 | 318 | public function getWeather() 319 | { 320 | $jsonString = '{ 321 | "jsonrpc":"2.0", 322 | "method":"FIM/getFunctionalItems", 323 | "params":[ 324 | ["devolo.WeatherWidget"],0 325 | ] 326 | }'; 327 | 328 | $answer = $this->sendCommand($jsonString); 329 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 330 | 331 | $data = $answer['result']['items'][0]['properties']; 332 | 333 | $this->_Weather = array(); 334 | $this->_Weather['currentTemp'] = $data['currentTemp']; 335 | 336 | unset($data['forecastData'][0]['weatherCode'] ); 337 | unset($data['forecastData'][1]['weatherCode'] ); 338 | unset($data['forecastData'][2]['weatherCode'] ); 339 | 340 | $this->_Weather['Today'] = $data['forecastData'][0]; 341 | $this->_Weather['Tomorrow'] = $data['forecastData'][1]; 342 | $this->_Weather['DayAfterT'] = $data['forecastData'][2]; 343 | 344 | $value = $data['lastUpdateTimestamp']; 345 | $this->_Weather['lastUpdate'] = $this->formatStates('LastActivity', 'lastActivityTime', $value); 346 | 347 | return array('result'=>$this->_Weather); 348 | } 349 | 350 | public function getMessageData($msg) 351 | { 352 | if ( is_string($msg) ) $msg = $this->getMessageByName($msg); 353 | if ( isset($msg['error']) ) return $msg; 354 | 355 | $answer = $this->fetchItems(array($msg['element'])); 356 | 357 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 358 | 359 | return array('result' => $answer['result']['items'][0]['properties']['msgData']); 360 | } 361 | 362 | public function getHueHSB($device) #Philips Hue 363 | { 364 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 365 | if ( isset($device['error']) ) return $device; 366 | 367 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true): null); 368 | if ($sensors == null) return array('result'=>null, 'error' => 'Unfound sensor for device'); 369 | 370 | foreach ($sensors as $sensor) 371 | { 372 | $sensorType = $this->getSensorType($sensor); 373 | 374 | if (in_array($sensorType, $this->_SensorsSendHSB)) 375 | { 376 | $answer = $this->fetchItems(array($sensor)); 377 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 378 | if ( isset($answer['result']['items'][0]['properties']['state']) ) 379 | { 380 | $hue = $answer['result']['items'][0]['properties']['hue']; 381 | $sat = $answer['result']['items'][0]['properties']['sat']; 382 | $bri = $answer['result']['items'][0]['properties']['bri']; 383 | return array('result' => array('hue' => $hue, 'sat' => $sat, 'bri' => $bri)); 384 | } 385 | } 386 | } 387 | return array('result'=>null, 'error' => 'Unfound OnOff sensor for device'); 388 | } 389 | 390 | public function getHueRGB($device) #Philips Hue 391 | { 392 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 393 | if ( isset($device['error']) ) return $device; 394 | 395 | $var = $this->getHueHSB($device); 396 | if ( isset($var['error']) ) return $var; 397 | 398 | $hue = $var['result']['hue']; 399 | $sat = $var['result']['sat']; 400 | $bri = $var['result']['bri']; 401 | 402 | #Convert Philips 65353 values: 403 | $hue = ($hue * 360) / 65535; 404 | $sat = ($sat * 100) / 65535; 405 | $bri = ($bri * 100) / 65535; 406 | 407 | $RGB = $this->HSLtoRGB($hue, $sat, $bri); 408 | return array('result' => $RGB); 409 | } 410 | 411 | 412 | //CONSUMPTION: 413 | public function logConsumption($filePath='/') 414 | { 415 | if (file_exists($filePath)) 416 | { 417 | $prevDatas = json_decode(file_get_contents($filePath), true); 418 | } 419 | else 420 | { 421 | $prevDatas = array(); 422 | } 423 | 424 | //get yesterday sums for each device: 425 | $yesterday = date('d.m.Y',strtotime('-1 days')); 426 | $datasArray = array(); 427 | foreach ($this->_AllDevices as $device) 428 | { 429 | if (strstr($device['model'], 'Wall:Plug:Switch:and:Meter')) 430 | { 431 | $name = $device['name']; 432 | $datas = $this->getDailyStat($device, 1); 433 | $sum = array_sum($datas['result'][0])/1000; 434 | $sum = $sum.'kWh'; 435 | $datasArray[$yesterday][$name] = $sum; 436 | } 437 | } 438 | 439 | //add yesterday sums to previously loaded datas: 440 | $prevDatas[$yesterday] = $datasArray[$yesterday]; 441 | 442 | //set recent up: 443 | $keys = array_keys($prevDatas); 444 | usort($keys, array('DevoloDHC','sortByDate')); 445 | $newArray = array(); 446 | foreach ($keys as $key) 447 | { 448 | $newArray[$key] = $prevDatas[$key]; 449 | } 450 | $prevDatas = $newArray; 451 | 452 | //write it to file: 453 | $put = file_put_contents($filePath, json_encode($prevDatas, JSON_PRETTY_PRINT)); 454 | if ($put) return array('result'=>$datasArray); 455 | return array('result'=>$datasArray, 'error'=>'Unable to write file!'); 456 | } 457 | 458 | private function sortByDate($a, $b) 459 | { 460 | $t1 = strtotime($a); 461 | $t2 = strtotime($b); 462 | return ($t2 - $t1); 463 | } 464 | 465 | public function getLogConsumption($filePath, $dateStart=null, $dateEnd=null) 466 | { 467 | if (file_exists($filePath)) 468 | { 469 | $prevDatas = json_decode(file_get_contents($filePath), true); 470 | $keys = array_keys($prevDatas); 471 | $logDateStart = $keys[0]; 472 | $logDateEnd = $keys[count($prevDatas)-1]; 473 | 474 | if (!isset($dateStart)) $dateStart = $logDateStart; 475 | if (!isset($dateEnd)) $dateEnd = $logDateEnd; 476 | 477 | $sumArray = array(); 478 | $c = count($prevDatas); 479 | for($i=0; $i<$c; $i++) 480 | { 481 | $thisDate = $keys[$i]; 482 | $data = $prevDatas[$thisDate]; 483 | if ( strtotime($thisDate)<=strtotime($dateStart) and strtotime($thisDate)>=strtotime($dateEnd)) 484 | { 485 | foreach ($data as $name => $value) 486 | { 487 | if (!isset($sumArray[$name])) $sumArray[$name] = 0; 488 | $sumArray[$name] += $value; 489 | } 490 | } 491 | } 492 | foreach ($sumArray as $name => $value) 493 | { 494 | $sumArray[$name] = $value.'kWh'; 495 | } 496 | return array('result'=>$sumArray); 497 | } 498 | else 499 | { 500 | return array('result'=>null, 'error'=>'Unable to open file!'); 501 | } 502 | } 503 | 504 | //SET: 505 | public function startScene($scene) 506 | { 507 | if ( is_string($scene) ) $scene = $this->getSceneByName($scene); 508 | if ( isset($scene['error']) ) return $scene; 509 | 510 | $element = $scene['element']; 511 | $answer = $this->invokeOperation($element, "start"); 512 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 513 | $result = ( ($answer['result'] == null) ? true : false ); 514 | return array('result'=>$result); 515 | } 516 | 517 | public function turnRuleOnOff($rule, $state=0) 518 | { 519 | if ( is_string($rule) ) $rule = $this->getRuleByName($rule); 520 | if ( isset($rule['error']) ) return $rule; 521 | 522 | $value = ( ($state == 0) ? 'false' : 'true' ); 523 | 524 | $jsonString = '{ 525 | "jsonrpc":"2.0", 526 | "method":"FIM/setProperty", 527 | "params":["'.$rule['element'].'","enabled",'.$value.']}'; 528 | 529 | $answer = $this->sendCommand($jsonString); 530 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 531 | return array('result'=>$answer); 532 | } 533 | 534 | public function turnTimerOnOff($timer, $state=0) 535 | { 536 | if ( is_string($timer) ) $timer = $this->getTimerByName($timer); 537 | if ( isset($timer['error']) ) return $timer; 538 | 539 | $value = ( ($state == 0) ? 'false' : 'true' ); 540 | 541 | $jsonString = '{ 542 | "jsonrpc":"2.0", 543 | "method":"FIM/setProperty", 544 | "params":["'.$timer['element'].'","enabled",'.$value.']}'; 545 | 546 | $answer = $this->sendCommand($jsonString); 547 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 548 | return array('result'=>$answer); 549 | } 550 | 551 | public function turnDeviceOnOff($device, $state=0) 552 | { 553 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 554 | if ( isset($device['error']) ) return $device; 555 | 556 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true) : null); 557 | if ($sensors == null) return array('result'=>null, 'error' => 'No sensor found in this device'); 558 | 559 | if ($state < 0) $state = 0; 560 | 561 | foreach ($sensors as $sensor) 562 | { 563 | $sensorType = $this->getSensorType($sensor); 564 | 565 | if (in_array($sensorType, $this->_SensorsOnOff)) 566 | { 567 | $operation = ($state == 0 ? 'turnOff' : 'turnOn'); 568 | $answer = $this->invokeOperation($sensor, $operation); 569 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 570 | return array('result'=>true); 571 | } 572 | if (in_array($sensorType, $this->_SensorsSend) and ($state == 1)) 573 | { 574 | $operation = "send"; 575 | $answer = $this->invokeOperation($sensor, $operation); 576 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 577 | return array('result'=>true); 578 | } 579 | } 580 | return array('result'=>null, 'error' => 'No supported sensor for this device'); 581 | } 582 | 583 | public function turnGroupOnOff($group, $state=0) 584 | { 585 | if ( is_string($group) ) $group = $this->getGroupByName($group); 586 | if ( isset($group['error']) ) return $group; 587 | 588 | $sensor = 'devolo.BinarySwitch:'.$group['id']; 589 | if ($state < 0) $state = 0; 590 | 591 | $operation = ($state == 0 ? 'turnOff' : 'turnOn'); 592 | $answer = $this->invokeOperation($sensor, $operation); 593 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 594 | return array('result'=>true); 595 | } 596 | 597 | public function setDeviceValue($device, $value) 598 | { 599 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 600 | if ( isset($device['error']) ) return $device; 601 | 602 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true) : null); 603 | if ($sensors == null) return array('result'=>null, 'error' => 'No sensor found in this device'); 604 | 605 | foreach ($sensors as $sensor) 606 | { 607 | $sensorType = $this->getSensorType($sensor); 608 | 609 | if (in_array($sensorType, $this->_SensorsSendValue)) 610 | { 611 | $operation = 'sendValue'; 612 | $answer = $this->invokeOperation($sensor, $operation, $value); 613 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 614 | return array('result'=>true); 615 | } 616 | } 617 | return array('result'=>null, 'error' => 'No supported sensor for this device'); 618 | } 619 | 620 | public function pressDeviceKey($device, $key=null) 621 | { 622 | if (!isset($key)) return array('result'=>null, 'error' => 'No key to press'); 623 | if ($key > 4) return array('result'=>null, 'error' => 'You really have Wall Switch with more than 4 buttons ? Let me know!'); 624 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 625 | if ( isset($device['error']) ) return $device; 626 | 627 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true) : null); 628 | if ($sensors == null) return array('result'=>null, 'error' => 'No sensor found in this device'); 629 | 630 | foreach($sensors as $sensor) 631 | { 632 | $sensorType = $this->getSensorType($sensor); 633 | if (in_array($sensorType, $this->_SensorsPressKey)) 634 | { 635 | $operation = 'pressKey'; 636 | $answer = $this->invokeOperation($sensor, $operation, $key); 637 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 638 | return array('result'=>true); 639 | } 640 | } 641 | return array('result'=>null, 'error' => 'No supported sensor for this device'); 642 | } 643 | 644 | public function sendMessage($msg) 645 | { 646 | if ( is_string($msg) ) $msg = $this->getMessageByName($msg); 647 | if ( isset($msg['error']) ) return $msg; 648 | 649 | $element = $msg['element']; 650 | $answer = $this->invokeOperation($element, "send"); 651 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 652 | $result = ( ($answer['result'] == null) ? true : false ); 653 | return array('result'=>$result); 654 | } 655 | 656 | public function setHueRGB($device, $rgb) #Philips Hue 657 | { 658 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 659 | if ( isset($device['error']) ) return $device; 660 | 661 | #check RGB array: 662 | $msg = 'Provide array(R,G,B) as 0-255 int value as second argument'; 663 | if (!is_array($rgb)) return array('result'=>null, 'error'=>$msg); 664 | if (count($rgb)!=3) return array('result'=>null, 'error'=>$msg); 665 | if (!is_int($rgb[0]) or !is_int($rgb[1]) or !is_int($rgb[2])) return array('result'=>null, 'error'=>$msg); 666 | 667 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true) : null); 668 | if ($sensors == null) return array('result'=>null, 'error' => 'No sensor found in this device'); 669 | 670 | foreach ($sensors as $sensor) 671 | { 672 | $sensorType = $this->getSensorType($sensor); 673 | 674 | if (in_array($sensorType, $this->_SensorsSendHSB)) 675 | { 676 | $HSL = $this->RGB2HueSB($rgb[0], $rgb[1], $rgb[2]); 677 | echo '
';##DEBUG 678 | var_dump($HSL);##DEBUG 679 | $value = '['.$HSL[0].','.$HSL[1].','.$HSL[2].']'; 680 | echo '
', $value;##DEBUG 681 | $operation = 'sendHSB'; 682 | $answer = $this->invokeOperation($sensor, $operation, $value); 683 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 684 | return array('result'=>true); 685 | } 686 | } 687 | return array('result'=>null, 'error' => 'No supported sensor for this device'); 688 | } 689 | 690 | //GET shorcuts: 691 | public function getDeviceByName($name) 692 | { 693 | foreach($this->_AllDevices as $thisDevice) 694 | { 695 | if ($thisDevice['name'] == $name) return $thisDevice; 696 | } 697 | return array('result'=>null, 'error' => 'Unfound device'); 698 | } 699 | 700 | public function getRuleByName($name) 701 | { 702 | if (count($this->_AllRules) == 0) $this->getRules(); 703 | 704 | foreach($this->_AllRules as $thisRule) 705 | { 706 | if ($thisRule['name'] == $name) return $thisRule; 707 | } 708 | return array('result'=>null, 'error' => 'Unfound rule'); 709 | } 710 | 711 | public function getTimerByName($name) 712 | { 713 | if (count($this->_AllTimers) == 0) $this->getTimers(); 714 | 715 | foreach($this->_AllTimers as $thisTimer) 716 | { 717 | if ($thisTimer['name'] == $name) return $thisTimer; 718 | } 719 | return array('result'=>null, 'error' => 'Unfound timer'); 720 | } 721 | 722 | public function getSceneByName($name) 723 | { 724 | if (count($this->_AllScenes) == 0) $this->getScenes(); 725 | 726 | foreach($this->_AllScenes as $thisScene) 727 | { 728 | if ($thisScene['name'] == $name) return $thisScene; 729 | } 730 | return array('result'=>null, 'error' => 'Unfound scene'); 731 | } 732 | 733 | public function getGroupByName($name) 734 | { 735 | foreach($this->_AllGroups as $thisGroup) 736 | { 737 | if ($thisGroup['name'] == $name) return $thisGroup; 738 | } 739 | return array('result'=>null, 'error' => 'Unfound group'); 740 | } 741 | 742 | public function getMessageByName($name) 743 | { 744 | if (count($this->_AllMessages) == 0) $this->getMessages(); 745 | 746 | foreach($this->_AllMessages['customMessages'] as $thisMsg) 747 | { 748 | if ($thisMsg['name'] == $name) return $thisMsg; 749 | } 750 | return array('result'=>null, 'error' => 'Unfound Message'); 751 | } 752 | 753 | //internal functions================================================== 754 | protected function getSensorType($sensor) 755 | { 756 | //devolo.BinarySensor:hdm:ZWave:D8F7DDE2/10 -> BinarySensor 757 | $sensorType = explode('devolo.', $sensor); 758 | if (count($sensorType) == 0) return null; 759 | $sensorType = explode(':', $sensorType[1]); 760 | $sensorType = $sensorType[0]; 761 | return $sensorType; 762 | } 763 | 764 | protected function getValuesByType($sensorType) 765 | { 766 | foreach($this->_SensorValuesByType as $type => $param) 767 | { 768 | if ($type == $sensorType) return $param; 769 | } 770 | return null; 771 | } 772 | 773 | public function resetSessionTimeout() 774 | { 775 | //cookie expire in 30min, anyway Devolo Central send resetSessionTimeout every 10mins 776 | if (!isset($this->_uuid)) 777 | { 778 | //get uuid: 779 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItemUIDs","params":["(objectClass=com.devolo.fi.page.Dashboard)"]}'; 780 | $answer = $this->sendCommand($jsonString); 781 | if (isset($answer['result'][0]) ) $uuid = $answer['result'][0]; 782 | else return array('error'=> array('message'=>"can't find uuid!")); 783 | $uuid = $answer['result'][0]; 784 | $uuid = explode('devolo.Dashboard.', $uuid)[1]; 785 | $this->_uuid = $uuid; 786 | } 787 | 788 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/invokeOperation","params":["devolo.UserPrefs.'.$this->_uuid.'","resetSessionTimeout",[]]}'; 789 | $answer = $this->sendCommand($jsonString); 790 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 791 | return array('result'=>$answer['result']); 792 | } 793 | 794 | public function debugDevice($device) 795 | { 796 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 797 | if ( isset($device['error']) ) return $device; 798 | 799 | $jsonArray = $this->fetchItems(array($device['uid'])); 800 | echo '
Device:
',json_encode($jsonArray, JSON_PRETTY_PRINT),'

'; 801 | 802 | $elements = $jsonArray['result']['items'][0]['properties']['elementUIDs']; 803 | $elementsArray = $this->fetchItems($elements); 804 | echo '
elementUIDs:
',json_encode($elementsArray, JSON_PRETTY_PRINT),'

'; 805 | 806 | $settings = $jsonArray['result']['items'][0]['properties']['settingUIDs']; 807 | $settingsArray = $this->fetchItems($settings); 808 | echo '
settingUIDs:
',json_encode($settingsArray, JSON_PRETTY_PRINT),'

'; 809 | } 810 | 811 | //color functions===================================================== 812 | protected function HSLtoRGB($hue, $sat, $val, $array = false, $format = 'rgb(%d, %d, %d)') 813 | { 814 | if ($hue < 0) $hue = 0; 815 | if ($hue > 360) $hue = 360; 816 | if ($sat < 0) $sat = 0; 817 | if ($sat > 100) $sat = 100; 818 | if ($val < 0) $val = 0; 819 | if ($val > 100) $val = 100; 820 | 821 | $dS = $sat/100.0; 822 | $dV = $val/100.0; 823 | $dC = $dV*$dS; 824 | $dH = $hue/60.0; 825 | $dT = $dH; 826 | 827 | while ($dT >= 2.0) $dT -= 2.0; 828 | $dX = $dC*(1-abs($dT-1)); 829 | 830 | switch(floor($dH)) 831 | { 832 | case 0: 833 | $dR = $dC; $dG = $dX; $dB = 0.0; break; 834 | case 1: 835 | $dR = $dX; $dG = $dC; $dB = 0.0; break; 836 | case 2: 837 | $dR = 0.0; $dG = $dC; $dB = $dX; break; 838 | case 3: 839 | $dR = 0.0; $dG = $dX; $dB = $dC; break; 840 | case 4: 841 | $dR = $dX; $dG = 0.0; $dB = $dC; break; 842 | case 5: 843 | $dR = $dC; $dG = 0.0; $dB = $dX; break; 844 | default: 845 | $dR = 0.0; $dG = 0.0; $dB = 0.0; break; 846 | } 847 | 848 | $dM = $dV - $dC; 849 | $dR += $dM; $dG += $dM; $dB += $dM; 850 | $dR *= 255; $dG *= 255; $dB *= 255; 851 | $rgb = ($array) ? array('R'=>round($dR), 'G'=>round($dG), 'B'=>round($dB)) : sprintf($format, round($dR), round($dG), round($dB)); 852 | 853 | return $rgb; 854 | } 855 | 856 | protected function RGB2HueSB ($R, $G, $B) 857 | { 858 | $var_R = ($R / 255); 859 | $var_G = ($G / 255); 860 | $var_B = ($B / 255); 861 | 862 | $var_Min = min($var_R, $var_G, $var_B); 863 | $var_Max = max($var_R, $var_G, $var_B); 864 | $del_Max = $var_Max - $var_Min; 865 | 866 | $V = $var_Max; 867 | if ($del_Max == 0) 868 | { 869 | $H = 0; 870 | $S = 0; 871 | } 872 | else 873 | { 874 | $S = $del_Max / $var_Max; 875 | 876 | $del_R = ( ( ( $var_Max - $var_R ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max; 877 | $del_G = ( ( ( $var_Max - $var_G ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max; 878 | $del_B = ( ( ( $var_Max - $var_B ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max; 879 | 880 | if ($var_R == $var_Max) $H = $del_B - $del_G; 881 | else if ($var_G == $var_Max) $H = ( 1 / 3 ) + $del_R - $del_B; 882 | else if ($var_B == $var_Max) $H = ( 2 / 3 ) + $del_G - $del_R; 883 | 884 | if ($H<0) $H++; 885 | if ($H>1) $H--; 886 | } 887 | 888 | $HSL = array(); 889 | $HSL[0] = round($H * 65535); 890 | $HSL[1] = round($S * 65535); 891 | $HSL[2] = round($V * 65535); 892 | return $HSL; 893 | } 894 | 895 | 896 | //getter functions==================================================== 897 | protected function getDevices() 898 | { 899 | if (count($this->_AllZones) == 0) 900 | { 901 | $result = $this->getZones(); 902 | if (isset($result['error'])) return $result; 903 | } 904 | 905 | //get all devices from all zones: 906 | $UIDSarray = array(); 907 | foreach ($this->_AllZones as $thisZone) 908 | { 909 | $thisDevices = $thisZone['deviceUIDs']; 910 | foreach ($thisDevices as $thisDevice) 911 | { 912 | $UIDSarray[] = $thisDevice; 913 | } 914 | } 915 | 916 | //request all infos for all devices at once: 917 | $jsonArray = $this->fetchItems($UIDSarray); 918 | 919 | //store devices: 920 | $devices = array(); 921 | foreach ($jsonArray['result']["items"] as $thisDevice) 922 | { 923 | $name = (isset($thisDevice['properties']['itemName']) ? $thisDevice['properties']['itemName'] : 'None'); 924 | $uid = (isset($thisDevice['UID']) ? $thisDevice['UID'] : 'None'); 925 | $elementUIDs = (isset($thisDevice['properties']['elementUIDs']) ? $thisDevice['properties']['elementUIDs'] : 'None'); 926 | 927 | $device = array('name' => $name, 928 | 'uid' => $uid, 929 | 'sensors' => json_encode($elementUIDs), 930 | 'zoneId' => (isset($thisDevice['properties']['zoneId']) ? $thisDevice['properties']['zoneId'] : 'None'), 931 | 'statUID' => (isset($thisDevice['properties']['statisticsUID']) ? $thisDevice['properties']['statisticsUID'] : 'None'), 932 | 'batteryLevel' => (isset($thisDevice['properties']['batteryLevel']) ? $thisDevice['properties']['batteryLevel'] : 'None'), 933 | 'model' => (isset($thisDevice['properties']['deviceModelUID']) ? $thisDevice['properties']['deviceModelUID'] : 'None') 934 | ); 935 | $devices[] = $device; 936 | } 937 | $this->_AllDevices = $devices; 938 | } 939 | 940 | protected function getZones() //also get groups! 941 | { 942 | $this->_AllZones = array(); 943 | $this->_AllGroups = array(); 944 | 945 | $jsonString = '{ 946 | "jsonrpc":"2.0", 947 | "method":"FIM/getFunctionalItems", 948 | "params":[ 949 | ["devolo.Grouping"],0 950 | ] 951 | }'; 952 | 953 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 954 | $jsonArray = json_decode($data, true); 955 | 956 | //avoid account with just demo gateway: 957 | if (!isset($jsonArray['result']["items"][0]['properties']['zones'])) 958 | { 959 | $this->error = 'Seems a demo Gateway, or no zones ?'; 960 | return array('result'=>null, 'error'=>$this->error); 961 | } 962 | 963 | //get all zones: 964 | $zones = $jsonArray['result']["items"][0]['properties']['zones']; 965 | foreach ($zones as $thisZone) 966 | { 967 | $thisID = $thisZone['id']; 968 | $thisName = $thisZone['name']; 969 | $thisDevices = $thisZone['deviceUIDs']; 970 | 971 | $zone = array('name' => $thisName, 972 | 'id' => $thisID, 973 | 'deviceUIDs' => $thisDevices 974 | ); 975 | $this->_AllZones[] = $zone; 976 | } 977 | 978 | //get each group infos: 979 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['smartGroupWidgetUIDs']); 980 | 981 | foreach ($jsonArray['result']['items'] as $thisGroup) 982 | { 983 | $thisID = $thisGroup['UID']; 984 | $thisName = $thisGroup['properties']['itemName']; 985 | $thisOurOfSync = $thisGroup['properties']['outOfSync']; 986 | $thisSync = $thisGroup['properties']['synchronized']; 987 | $thisDevices = $thisGroup['properties']['deviceUIDs']; 988 | 989 | $group = array('name' => $thisName, 990 | 'id' => $thisID, 991 | 'outOfSync' => $thisOurOfSync, 992 | 'synchronized' => $thisSync, 993 | 'deviceUIDs' => $thisDevices 994 | ); 995 | $this->_AllGroups[] = $group; 996 | } 997 | } 998 | 999 | protected function getScenes() 1000 | { 1001 | $this->_AllScenes = array(); 1002 | 1003 | $jsonString = '{ 1004 | "jsonrpc":"2.0", 1005 | "method":"FIM/getFunctionalItems", 1006 | "params":[ 1007 | ["devolo.Scene"],0 1008 | ] 1009 | }'; 1010 | 1011 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1012 | $jsonArray = json_decode($data, true); 1013 | 1014 | //request datas for all scenes: 1015 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['sceneUIDs']); 1016 | 1017 | foreach($jsonArray['result']['items'] as $thisScene) 1018 | { 1019 | $scene = array('name' => $thisScene['properties']['itemName'], 1020 | 'id' => $thisScene['UID'], 1021 | 'element' => str_replace('Scene', 'SceneControl', $thisScene['UID']) 1022 | ); 1023 | array_push($this->_AllScenes, $scene); 1024 | } 1025 | } 1026 | 1027 | protected function getTimers() 1028 | { 1029 | $this->_AllTimers = array(); 1030 | 1031 | $jsonString = '{ 1032 | "jsonrpc":"2.0", 1033 | "method":"FIM/getFunctionalItems", 1034 | "params":[ 1035 | ["devolo.Schedules"],0 1036 | ] 1037 | }'; 1038 | 1039 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1040 | $jsonArray = json_decode($data, true); 1041 | 1042 | //request datas for all rules: 1043 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['scheduleUIDs']); 1044 | 1045 | foreach($jsonArray['result']['items'] as $thisTimer) 1046 | { 1047 | $rule = array('name' => $thisTimer['properties']['itemName'], 1048 | 'id' => $thisTimer['UID'], 1049 | 'element' => str_replace('Schedule', 'ScheduleControl', $thisTimer['UID']) 1050 | ); 1051 | array_push($this->_AllTimers, $rule); 1052 | } 1053 | } 1054 | 1055 | protected function getRules() 1056 | { 1057 | $this->_AllRules = array(); 1058 | 1059 | $jsonString = '{ 1060 | "jsonrpc":"2.0", 1061 | "method":"FIM/getFunctionalItems", 1062 | "params":[ 1063 | ["devolo.Services"],0 1064 | ] 1065 | }'; 1066 | 1067 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1068 | $jsonArray = json_decode($data, true); 1069 | 1070 | //request datas for all rules: 1071 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['serviceUIDs']); 1072 | 1073 | foreach($jsonArray['result']['items'] as $thisRule) 1074 | { 1075 | $rule = array('name' => $thisRule['properties']['itemName'], 1076 | 'id' => $thisRule['UID'], 1077 | 'element' => str_replace('Service', 'ServiceControl', $thisRule['UID']) 1078 | ); 1079 | array_push($this->_AllRules, $rule); 1080 | } 1081 | } 1082 | 1083 | protected function getMessages() 1084 | { 1085 | $this->_AllMessages = array(); 1086 | 1087 | $jsonString = '{ 1088 | "jsonrpc":"2.0", 1089 | "method":"FIM/getFunctionalItems", 1090 | "params":[ 1091 | ["devolo.Messages"],0 1092 | ] 1093 | }'; 1094 | 1095 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1096 | $jsonArray = json_decode($data, true); 1097 | 1098 | $this->_AllMessages['pnEndpoints'] = $jsonArray['result']['items'][0]['properties']['pnEndpoints']; 1099 | $this->_AllMessages['phoneNumbers'] = $jsonArray['result']['items'][0]['properties']['phoneNumbers']; 1100 | $this->_AllMessages['emailExt'] = $jsonArray['result']['items'][0]['properties']['emailExt']; 1101 | $this->_AllMessages['emailAddresses'] = $jsonArray['result']['items'][0]['properties']['emailAddresses']; 1102 | 1103 | //fetch custom Messages: 1104 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['customMessageUIDs']); 1105 | 1106 | $this->_AllMessages['customMessages'] = array(); 1107 | foreach($jsonArray['result']['items'] as $thisMsg) 1108 | { 1109 | $msg = array('name' => $thisMsg['properties']['itemName'], 1110 | 'id' => $thisMsg['UID'], 1111 | 'description' => $thisMsg['properties']['description'], 1112 | 'base' => $thisMsg['properties']['base'], 1113 | 'element' => $thisMsg['properties']['elementUIDs'][0] 1114 | ); 1115 | array_push($this->_AllMessages['customMessages'], $msg); 1116 | } 1117 | } 1118 | 1119 | protected function formatStates($sensorType, $key, $value) 1120 | { 1121 | if ($sensorType=='Meter' and $key=='totalValue') return $value.'kWh'; 1122 | if ($sensorType=='Meter' and $key=='currentValue') return $value.'W'; 1123 | if ($key=='sinceTime') 1124 | { 1125 | $ts = $value; 1126 | $ts = substr($ts, 0, -3) - 3600; //microtime timestamp from Berlin 1127 | $date = new DateTime(); 1128 | $date->setTimestamp($ts); 1129 | $date->setTimezone(new DateTimeZone(date_default_timezone_get())); //set it to php server timezone 1130 | $date = $date->format('d.m.Y H:i'); 1131 | return $date; 1132 | } 1133 | if ($sensorType=='LastActivity' and $key=='lastActivityTime') 1134 | { 1135 | if ($value == -1) return 'Never'; 1136 | //convert javascript timestamp to date: 1137 | $ts = $value; 1138 | $ts = substr($ts, 0, -3) - 3600; //microtime timestamp from Berlin 1139 | $date = new DateTime(); 1140 | $date->setTimestamp($ts); 1141 | $date->setTimezone(new DateTimeZone(date_default_timezone_get())); //set it to php server timezone 1142 | 1143 | //format it: 1144 | $nowDate = new DateTime(); 1145 | $interval = $nowDate->diff($date)->days; 1146 | switch($interval) { 1147 | case 0: 1148 | $date = 'Today '.$date->format('H:i'); 1149 | break; 1150 | case -1: 1151 | $date = 'Yesterday '.$date->format('H:i'); 1152 | break; 1153 | default: 1154 | $date = $date->format('d.m.Y H:i'); 1155 | } 1156 | return $date; 1157 | } 1158 | return $value; 1159 | } 1160 | 1161 | 1162 | //calling functions=================================================== 1163 | protected function _request($method, $host, $path, $jsonString=null, $postinfo=null) //standard function handling all get/post request with curl | return string 1164 | { 1165 | if (!isset($this->_curlHdl)) 1166 | { 1167 | $this->_curlHdl = curl_init(); 1168 | curl_setopt($this->_curlHdl, CURLOPT_URL, $this->_authUrl); 1169 | 1170 | curl_setopt($this->_curlHdl, CURLOPT_COOKIEJAR, $this->_cookFile); 1171 | curl_setopt($this->_curlHdl, CURLOPT_COOKIEFILE, $this->_cookFile); 1172 | 1173 | curl_setopt($this->_curlHdl, CURLOPT_SSL_VERIFYHOST, false); 1174 | curl_setopt($this->_curlHdl, CURLOPT_SSL_VERIFYPEER, false); 1175 | 1176 | curl_setopt($this->_curlHdl, CURLOPT_RETURNTRANSFER, true); 1177 | curl_setopt($this->_curlHdl, CURLOPT_FOLLOWLOCATION, true); 1178 | 1179 | curl_setopt($this->_curlHdl, CURLOPT_REFERER, 'http://www.google.com/'); 1180 | curl_setopt($this->_curlHdl, CURLOPT_USERAGENT, 'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0'); 1181 | 1182 | curl_setopt($this->_curlHdl, CURLOPT_ENCODING , "gzip"); 1183 | } 1184 | 1185 | $url = filter_var($host.$path, FILTER_SANITIZE_URL); 1186 | 1187 | curl_setopt($this->_curlHdl, CURLOPT_URL, $url); 1188 | 1189 | if ($method == 'POST') 1190 | { 1191 | curl_setopt($this->_curlHdl, CURLOPT_RETURNTRANSFER, true); 1192 | curl_setopt($this->_curlHdl, CURLOPT_POST, true); 1193 | } 1194 | else 1195 | { 1196 | curl_setopt($this->_curlHdl, CURLOPT_POST, false); 1197 | } 1198 | 1199 | if ( isset($jsonString) ) 1200 | { 1201 | $jsonString = str_replace('"jsonrpc":"2.0",', '"jsonrpc":"2.0", "id":'.$this->_POSTid.',', $jsonString); 1202 | $this->_POSTid++; 1203 | curl_setopt($this->_curlHdl, CURLOPT_HEADER, false); 1204 | curl_setopt($this->_curlHdl, CURLINFO_HEADER_OUT, false ); 1205 | curl_setopt($this->_curlHdl, CURLOPT_POST, false); 1206 | curl_setopt($this->_curlHdl, CURLOPT_CUSTOMREQUEST, 'POST'); 1207 | curl_setopt($this->_curlHdl, CURLOPT_POSTFIELDS, $jsonString); 1208 | } 1209 | 1210 | if ( isset($postinfo) ) 1211 | { 1212 | curl_setopt($this->_curlHdl, CURLOPT_POSTFIELDS, $postinfo); 1213 | } 1214 | 1215 | $response = curl_exec($this->_curlHdl); 1216 | 1217 | //$info = curl_getinfo($this->_curlHdl); 1218 | //echo "
cURL info".json_encode($info, JSON_PRETTY_PRINT)."

"; 1219 | 1220 | $this->error = null; 1221 | if ($response === false) $this->error = curl_error($this->_curlHdl); 1222 | return $response; 1223 | } 1224 | 1225 | protected function fetchItems($UIDSarray) //get infos from central for array of device, sensor, timer etc | return array 1226 | { 1227 | $devicesJson = json_encode($UIDSarray); 1228 | $jsonString = '{ 1229 | "jsonrpc":"2.0", 1230 | "method":"FIM/getFunctionalItems", 1231 | "params":[ 1232 | '.$devicesJson.',0 1233 | ] 1234 | }'; 1235 | 1236 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1237 | $jsonArray = json_decode($data, true); 1238 | return $jsonArray; 1239 | } 1240 | 1241 | protected function invokeOperation($sensor, $operation, $value=null) //sensor string, authorized operation string | return array 1242 | { 1243 | $value = '['.$value.']'; 1244 | $jsonString = '{ 1245 | "jsonrpc":"2.0", 1246 | "method":"FIM/invokeOperation", 1247 | "params":["'.$sensor.'","'.$operation.'",'.$value.']}'; 1248 | 1249 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1250 | $jsonArray = json_decode($data, true); 1251 | return $jsonArray; 1252 | } 1253 | 1254 | public function sendCommand($jsonString) //directly send json to central. Only works when all required authorisations are set | return array 1255 | { 1256 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1257 | $jsonArray = json_decode($data, true); 1258 | return $jsonArray; 1259 | } 1260 | 1261 | //functions authorization============================================= 1262 | 1263 | //user central stuff: 1264 | public $_userInfos; 1265 | public $_centralInfos; 1266 | public $_gateway; 1267 | public $_uuid = null; 1268 | public $_token; 1269 | public $error = null; 1270 | public $_wasCookiesLoaded = false; 1271 | public $_cookFile = ''; 1272 | public $_gateIdx = 0; 1273 | 1274 | //central stuff stuff(!): 1275 | public $_AllDevices = null; 1276 | public $_AllZones = null; 1277 | public $_AllGroups = null; 1278 | public $_AllRules = null; 1279 | public $_AllTimers = null; 1280 | public $_AllScenes = null; 1281 | public $_AllMessages = null; 1282 | public $_Weather = null; 1283 | 1284 | //authentication: 1285 | protected $_login; 1286 | protected $_password; 1287 | protected $_authUrl = 'https://www.mydevolo.com'; 1288 | protected $_dhcUrl = 'https://homecontrol.mydevolo.com'; 1289 | protected $_lang = '/en'; 1290 | protected $_POSTid = 0; 1291 | protected $_curlHdl = null; 1292 | 1293 | //types stuff: 1294 | /* 1295 | Devolo Home Control Portal(web interface or app interface to access HCB Home Control Box) 1296 | -> HCB 1297 | ->Device 1298 | - sensor (type, data), handle operations ? 1299 | - sensor (type, data), handle operations ? 1300 | ->Device 1301 | - sensor (type, data), handle operations ? 1302 | etc 1303 | */ 1304 | protected $_SensorsOnOff = array('BinarySwitch', 'BinarySensor', 'HueBulbSwitch'); //supported sensor types for on/off operation 1305 | protected $_SensorsSend = array('HttpRequest'); //supported sensor types for send operation 1306 | protected $_SensorsSendValue = array('MultiLevelSwitch', 'SirenMultiLevelSwitch'); //supported sensor types for sendValue operation 1307 | protected $_SensorsPressKey = array('RemoteControl'); //supported sensor types for pressKey operation 1308 | protected $_SensorsSendHSB = array('HueBulbColor'); //supported sensor types for sendHSB operation 1309 | 1310 | protected $_SensorsNoValues = array('HttpRequest'); //virtual device sensor 1311 | 1312 | protected $_SensorValuesByType = array( 1313 | 'Meter' => array('sensorType', 'currentValue', 'totalValue', 'sinceTime'), 1314 | 'BinarySwitch' => array('switchType', 'state', 'targetState'), 1315 | 'MildewSensor' => array('sensorType', 'state'), 1316 | 'BinarySensor' => array('sensorType', 'state'), 1317 | 'SirenBinarySensor' => array('sensorType', 'state'), 1318 | 'MultiLevelSensor' => array('sensorType', 'value'), 1319 | 'HumidityBarZone' => array('sensorType', 'value'), 1320 | 'DewpointSensor' => array('sensorType', 'value'), 1321 | 'HumidityBarValue' => array('sensorType', 'value'), 1322 | 'SirenMultiLevelSensor' => array('sensorType', 'value'), 1323 | 'SirenMultiLevelSwitch' => array('switchType', 'targetValue'), 1324 | 'MultiLevelSwitch' => array('switchType', 'value', 'targetValue', 'min', 'max'), 1325 | 'RemoteControl' => array('keyCount', 'keyPressed'), 1326 | 'HueBulbSwitch' => array('sensorType', 'state'), 1327 | 'HueBulbColor' => array('switchType', 'hue', 'sat', 'bri', 'targetHsb'), 1328 | 'LastActivity' => array('lastActivityTime') 1329 | ); 1330 | 1331 | protected function getCSRF($htmlString) 1332 | { 1333 | $dom = new DOMDocument(); 1334 | @$dom->loadHTML($htmlString); 1335 | $nodes = $dom->getElementsByTagName('input'); 1336 | foreach($nodes as $node) 1337 | { 1338 | if ($node->hasAttributes()) 1339 | { 1340 | foreach($node->attributes as $attribute) 1341 | { 1342 | if ($attribute->nodeName == 'type' && $attribute->nodeValue == 'hidden') 1343 | { 1344 | $name = $node->getAttribute('name'); 1345 | if (stripos($name, 'csrf') !== false) return $node->getAttribute('value'); 1346 | } 1347 | } 1348 | } 1349 | } 1350 | return False; 1351 | } 1352 | 1353 | protected function cookies_are_hot() 1354 | { 1355 | if ( is_writable(__DIR__) ) //API can write in his folder 1356 | { 1357 | $this->_cookFile = __DIR__.'/dhc_cookies.txt'; 1358 | 1359 | if ( is_writable($this->_cookFile) and (time()-filemtime($this->_cookFile) < 1200) ) //cookie file exist and is younger than 20mins 1360 | { 1361 | //return true; //no check is 0.15s faster! 1362 | $var = file_get_contents($this->_cookFile); 1363 | if (strstr($var, 'JSESSIONID')) 1364 | { 1365 | $answer = $this->resetSessionTimeout(); 1366 | if ( !isset($answer['error']['message']) ) 1367 | { 1368 | $this->_wasCookiesLoaded = true; 1369 | return true; 1370 | } 1371 | else 1372 | { 1373 | curl_close($this->_curlHdl); //was initialized by resetSessionTimeout and will keep old cookies file! 1374 | $this->_curlHdl = null; 1375 | @unlink($this->_cookFile); 1376 | return false; 1377 | } 1378 | } 1379 | } 1380 | if ( is_writable($this->_cookFile) ) unlink($this->_cookFile); 1381 | } 1382 | else 1383 | { 1384 | $this->_wasCookiesLoaded = 'Unable to write cookies file'; 1385 | return false; 1386 | } 1387 | return false; 1388 | } 1389 | 1390 | protected function auth() 1391 | { 1392 | if ($this->cookies_are_hot()) return true; 1393 | //No young cookie file, full authentication: 1394 | 1395 | //___________get CSRF_______________________________________________________ 1396 | $response = $this->_request('GET', $this->_authUrl, $this->_lang, null); 1397 | 1398 | if($response==false) 1399 | { 1400 | $this->error = "Can't connect to Devolo servers."; 1401 | return false; 1402 | } 1403 | 1404 | $csrf = $this->getCSRF($response); 1405 | if ($csrf != false) 1406 | { 1407 | $this->_csrf = $csrf; 1408 | } 1409 | else 1410 | { 1411 | $this->error = "Couldn't find Devolo CSRF."; 1412 | return false; 1413 | } 1414 | 1415 | 1416 | //___________post login/password____________________________________________ 1417 | $postinfo = '_csrf='.$csrf.'&username='.$this->_login.'&password='.$this->_password; 1418 | $response = $this->_request('POST', $this->_authUrl, $this->_lang, null, $postinfo); 1419 | 1420 | 1421 | //___________get gateway____________________________________________________ 1422 | $path = $this->_lang.'/hc/gateways/status'; 1423 | $response = $this->_request('GET', $this->_authUrl, $path, null); 1424 | $json = json_decode($response, true); 1425 | 1426 | if (isset($json['data'][$this->_gateIdx]['id'])) 1427 | { 1428 | $gateway = $json['data'][$this->_gateIdx]['id']; 1429 | $this->_gateway = $gateway; 1430 | } 1431 | else 1432 | { 1433 | $this->error = "Couldn't find Devolo gateway."; 1434 | return false; 1435 | } 1436 | 1437 | //___________get open Gateway_______________________________________________ 1438 | $path = $this->_lang.'/hc/gateways/'.$gateway.'/open'; 1439 | $response = $this->_request('GET', $this->_authUrl, $path, null, null); 1440 | 1441 | return true; 1442 | } 1443 | 1444 | function __construct($login, $password, $connect=true, $gateIdx=0) 1445 | { 1446 | $this->_login = urlencode($login); 1447 | $this->_password = urlencode($password); 1448 | $this->_gateIdx = $gateIdx; 1449 | 1450 | if ($connect==true) 1451 | { 1452 | if ($this->auth() == true) $this->getDevices(); 1453 | } 1454 | } 1455 | 1456 | /* 1457 | dynamic call to getAllxxx / $_DHC->getAllDevices(); 1458 | if _AllDevices is null, call getDevices, return _AllDevices 1459 | 1460 | getAllDevices() / getAllZones() / getAllGroups() / getAllRules() / getAllTimers() / getAllScenes() / getAllMessages() 1461 | */ 1462 | public function __call($name, $args) 1463 | { 1464 | if (preg_match('/^get(.+)/', $name, $matches)) 1465 | { 1466 | $var_name = '_'.$matches[1]; 1467 | $fn_name = substr($var_name, 4); 1468 | 1469 | if (@count($this->$var_name) == 0) 1470 | { 1471 | $this->$var_name = 'Undefined'; 1472 | call_user_func(array($this, 'get'.$fn_name)); 1473 | } 1474 | //unknown var/function: 1475 | return array('result'=>$this->$var_name); 1476 | } 1477 | //no get, no function! 1478 | return array('result'=>null, 'error'=>'Undefined function'); 1479 | } 1480 | 1481 | //DevoloDHC end 1482 | } 1483 | 1484 | ?> 1485 | -------------------------------------------------------------------------------- /class/phpDevoloAPI.php: -------------------------------------------------------------------------------- 1 | isDeviceOn('MyPlug'); 17 | if (isset($state['error'])) echo $state['error']; 18 | else echo "Device state:".$state['result']; 19 | */ 20 | 21 | //user functions====================================================== 22 | 23 | public function getInfos() //@return['result'] array infos from this api, Devolo user, and Devolo central 24 | { 25 | 26 | if (!isset($this->_userInfos)) 27 | { 28 | //get uuid: 29 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItemUIDs","params":["(objectClass=com.devolo.fi.page.Dashboard)"]}'; 30 | $answer = $this->sendCommand($jsonString); 31 | $uuid = $answer['result'][0]; 32 | $uuid = explode('devolo.Dashboard.', $uuid)[1]; 33 | $this->_uuid = $uuid; 34 | 35 | //get user infos: 36 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItems","params":[["devolo.UserPrefs.'.$this->_uuid.'"],0]}'; 37 | $answer = $this->sendCommand($jsonString); 38 | $this->_userInfos = $answer['result']['items'][0]['properties']; 39 | } 40 | 41 | if (!isset($this->_centralInfos)) 42 | { 43 | //get portal manager token 44 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItemUIDs","params":["(objectClass=com.devolo.fi.gw.PortalManager)"]}'; 45 | $answer = $this->sendCommand($jsonString); 46 | if ( isset($answer['result'][0]) ) 47 | { 48 | $var = $answer['result'][0]; 49 | $this->_token = str_replace('devolo.mprm.gw.PortalManager.', '', $var); 50 | } 51 | else return array('error'=>'Could not find info token.'); 52 | 53 | //get central infos: 54 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItems","params":[["devolo.mprm.gw.PortalManager.'.$this->_token.'"],0]}'; 55 | $answer = $this->sendCommand($jsonString); 56 | 57 | $centralInfos = 'None'; 58 | if ( isset($answer['result']['items'][0]['properties']) ) 59 | { 60 | $this->_centralInfos = $answer['result']['items'][0]['properties']; 61 | $this->_gateway = $this->_centralInfos['gateway']; 62 | } 63 | } 64 | 65 | $infos = array( 66 | 'phpAPI version' => $this->_version, 67 | 'user' => $this->_userInfos, 68 | 'central' => $this->_centralInfos 69 | ); 70 | return array('result'=>$infos); 71 | } 72 | 73 | public function getNumStats() //@return['result'] array containing number of devices, rules, etc... 74 | { 75 | if (count($this->_AllRules) == 0) $this->getRules(); 76 | if (count($this->_AllTimers) == 0) $this->getTimers(); 77 | if (count($this->_AllScenes) == 0) $this->getScenes(); 78 | if (count($this->_AllMessages) == 0) $this->getMessages(); 79 | 80 | $report = array( 81 | 'Devices' => count($this->_AllDevices), 82 | 'Rules' => count($this->_AllRules), 83 | 'Timers' => count($this->_AllTimers), 84 | 'Scenes' => count($this->_AllScenes), 85 | 'Groups' => count($this->_AllGroups), 86 | 'Messages' => count($this->_AllMessages), 87 | 'Zones' => count($this->_AllZones) 88 | ); 89 | return array('result'=>$report); 90 | } 91 | 92 | //______________________IS: 93 | 94 | public function isRuleActive($rule) //@rule name | @return['result'] string active/inactive 95 | { 96 | if ( is_string($rule) ) $rule = $this->getRuleByName($rule); 97 | if ( isset($rule['error']) ) return $rule; 98 | 99 | $answer = $this->fetchItems(array($rule['element'])); 100 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 101 | $state = $answer['result']['items'][0]['properties']['enabled']; 102 | $state = ($state > 0 ? 'active' : 'inactive'); 103 | return array('result'=>$state); 104 | } 105 | 106 | public function isTimerActive($timer) //@timer name | @return['result'] string active/inactive 107 | { 108 | if ( is_string($timer) ) $timer = $this->getTimerByName($timer); 109 | if ( isset($timer['error']) ) return $timer; 110 | 111 | return $this->isRuleActive($timer); 112 | } 113 | 114 | public function isDeviceOn($device, $switch=null) //@device name | @return['result'] string on/off 115 | { 116 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 117 | if ( isset($device['error']) ) return $device; 118 | 119 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true): null); 120 | if ($sensors == null) return array('result'=>null, 'error' => 'Unfound sensor for device'); 121 | 122 | foreach ($sensors as $sensor) 123 | { 124 | $sensorType = $this->getSensorType($sensor); 125 | 126 | if (in_array($sensorType, $this->_SensorsOnOff)) 127 | { 128 | //check qubino 2 relay: 129 | if ($switch != null) 130 | { 131 | $thisSwitch = substr($sensor, -2); 132 | //several switches detected? 133 | if ($thisSwitch != '#1' and $thisSwitch != '#2') return array('result'=>null, 'error' => 'This switch does not seem to have several contacts'); 134 | //get the other switch: 135 | if ($thisSwitch == '#1') $otherSensor = str_replace('#1', '#2', $sensor); 136 | if ($thisSwitch == '#2') $otherSensor = str_replace('#2', '#1', $sensor); 137 | //so, which swhit(ches) to fetch: 138 | if ($switch == 'All') 139 | { 140 | $toFetch = array($sensor, $otherSensor); 141 | $answer = $this->fetchItems($toFetch); 142 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 143 | $state1 = $answer['result']['items'][0]['properties']['state']; 144 | $state2 = $answer['result']['items'][1]['properties']['state']; 145 | $isOn1 = ($state1 > 0 ? 'on' : 'off'); 146 | $isOn2 = ($state2 > 0 ? 'on' : 'off'); 147 | return array('result' => array($isOn1, $isOn2)); 148 | } 149 | if (($switch == 1 and $thisSwitch == '#1') or ($switch == 2 and $thisSwitch == '#2')) 150 | { 151 | $toFetch = array($sensor); 152 | } 153 | else 154 | { 155 | $toFetch = array($otherSensor); 156 | } 157 | 158 | $answer = $this->fetchItems($toFetch); 159 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 160 | if (isset($answer['result']['items'][0]['properties']['state'])) 161 | { 162 | $state = $answer['result']['items'][0]['properties']['state']; 163 | $isOn = ($state > 0 ? 'on' : 'off'); 164 | return array('result' => $isOn); 165 | } 166 | } 167 | else //single sensor request: 168 | { 169 | $answer = $this->fetchItems(array($sensor)); 170 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 171 | if (isset($answer['result']['items'][0]['properties']['state'])) 172 | { 173 | $state = $answer['result']['items'][0]['properties']['state']; 174 | $isOn = ($state > 0 ? 'on' : 'off'); 175 | return array('result' => $isOn); 176 | } 177 | } 178 | } 179 | } 180 | return array('result'=>null, 'error' => 'Unfound OnOff sensor for device'); 181 | } 182 | 183 | //______________________GET: 184 | 185 | public function getDeviceStates($device, $DebugReport=null) //@return['result'] array of sensor type and state 186 | { 187 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 188 | if ( isset($device['error']) ) return $device; 189 | 190 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true) : null); 191 | if ($sensors == null) return array('result'=>null, 'error' => 'Unfound device'); 192 | 193 | //fetch sensors: 194 | $arrayStates = array(); 195 | foreach($sensors as $sensor) 196 | { 197 | $sensorType = $this->getSensorType($sensor); 198 | $param = $this->getValuesByType($sensorType); 199 | if ($param != null) 200 | { 201 | $answer = $this->fetchItems(array($sensor)); 202 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 203 | if ($DebugReport == true) echo '
'.json_encode($answer, JSON_PRETTY_PRINT).'

'; 204 | $jsonSensor = array('sensorType' => $sensorType); 205 | foreach ($param as $key) 206 | { 207 | $value = $answer['result']['items'][0]['properties'][$key]; 208 | //Seems Devolo doesn't know all about its own motion sensor... 209 | if ($key=='sensorType' and $value=='unknown') continue; 210 | $value = $this->formatStates($sensorType, $key, $value); 211 | $jsonSensor[$key] = $value; 212 | } 213 | $arrayStates[] = $jsonSensor; 214 | } 215 | elseif ( !in_array($sensorType, $this->_SensorsNoValues) ) //Unknown, unsupported sensor! 216 | { 217 | $answer = $this->fetchItems(array($sensor)); 218 | echo "DEBUG - UNKNOWN PARAM - Please help and report this message on https://github.com/KiboOst/php-devoloDHC or email it to ".base64_decode('a2lib29zdEBmcmVlLmZy')."
"; 219 | echo '
infos:'.json_encode($answer, JSON_PRETTY_PRINT).'

'; 220 | } 221 | } 222 | return array('result'=>$arrayStates); 223 | } 224 | 225 | public function getDeviceData($device, $askData=null) //@device name | @return['result'] sensor data. If not asked data, @return['available'] all available sensors/data array 226 | { 227 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 228 | if ( isset($device['error']) ) return $device; 229 | 230 | $datas = $this->getDeviceStates($device); 231 | $availableDatas = array(); 232 | foreach ($datas['result'] as $item) 233 | { 234 | array_push($availableDatas, $item['sensorType']); 235 | @array_push($availableDatas, $item['switchType']); 236 | if ($item['sensorType'] == $askData or @$item['switchType'] == $askData) return array('result'=>$item); 237 | } 238 | $error = array('result'=>null, 239 | 'error' => 'Unfound data for this Device', 240 | 'available' => $availableDatas 241 | ); 242 | return $error; 243 | } 244 | 245 | public function getDevicesByZone($zoneName) //@zone name | @return['result'] array of devices 246 | { 247 | foreach($this->_AllZones as $thisZone) 248 | { 249 | if ($thisZone['name'] == $zoneName) 250 | { 251 | $devicesUIDS = $thisZone['deviceUIDs']; 252 | $jsonArray = array(); 253 | foreach ($this->_AllDevices as $thisDevice) 254 | { 255 | if (in_array($thisDevice['uid'], $devicesUIDS)) $jsonArray[] = $thisDevice; 256 | } 257 | return array('result'=>$jsonArray); 258 | } 259 | } 260 | return array('result'=>null, 'error'=>'Unfound '.$zoneName); 261 | } 262 | 263 | public function getDeviceURL($device) //@device name | @return['result'] string 264 | { 265 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 266 | if ( isset($device['error']) ) return $device; 267 | 268 | $uid = $device['uid']; 269 | if (!stristr($uid, 'hdm:DevoloHttp:virtual')) return array('result'=>null, 'error' => 'This is not an http virtual device'); 270 | 271 | $hdm = str_replace('hdm:DevoloHttp:virtual', 'hs.hdm:DevoloHttp:virtual', $uid); 272 | $answer = $this->fetchItems(array($hdm)); 273 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 274 | $url = $answer['result']['items'][0]['properties']['httpSettings']['request']; 275 | return array('result'=>$url); 276 | } 277 | 278 | public function getDeviceBattery($device) //@device name | @return['result'] string 279 | { 280 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 281 | if ( isset($device['error']) ) return $device; 282 | 283 | $batLevel = $device['batteryLevel']; 284 | if ($batLevel == 'None' or $batLevel == -1) $batLevel = 'No battery'; 285 | 286 | return array('result'=>$batLevel); 287 | } 288 | 289 | public function getAllBatteries($lowLevel=100, $filter=1) //@return['result'] array of device name / battery level under $lowLevel. $filter other than 1 return even no battery devices. 290 | { 291 | $jsonDatas = array(); 292 | $c = count($this->_AllDevices); 293 | foreach ($this->_AllDevices as $thisDevice) 294 | { 295 | $thisDeviceName = $thisDevice['name'] ; 296 | $thisBatLevel = $thisDevice['batteryLevel']; 297 | if (($thisBatLevel == -1) or ($thisBatLevel == 'None')) {if ($filter==1) continue; } 298 | 299 | $datas = array('name' => $thisDeviceName, 'battery_percent' => $thisBatLevel); 300 | if ($thisBatLevel <= $lowLevel) array_push($jsonDatas, $datas); 301 | } 302 | return array('result'=>$jsonDatas); 303 | } 304 | 305 | public function getDailyDiary($numEvents=20) //@number of events to return | @return['result'] array of daily events 306 | { 307 | if (!is_int($numEvents)) return array('error'=> 'Provide numeric argument as number of events to report'); 308 | if ($numEvents < 0) return array('error'=> 'Dude, what should I report as negative number of events ? Are you in the future ?'); 309 | 310 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/invokeOperation","params":["devolo.DeviceEvents","retrieveDailyData",[0,0,'.$numEvents.']]}'; 311 | $answer = $this->sendCommand($jsonString); 312 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 313 | 314 | $jsonDatas = array(); 315 | $numEvents = count($answer['result'])-1; //may have less than requested 316 | foreach (array_reverse($answer['result']) as $event) 317 | { 318 | $deviceName = $event['deviceName']; 319 | $deviceZone = $event['deviceZone']; 320 | $author = $event['author']; 321 | $timeOfDay = $event['timeOfDay']; 322 | $timeOfDay = gmdate('H:i:s', $timeOfDay); 323 | 324 | $datas = array( 325 | 'deviceName' => $deviceName, 326 | 'deviceZone' => $deviceZone, 327 | 'author' => $author, 328 | 'timeOfDay' => $timeOfDay 329 | ); 330 | $jsonDatas[] = $datas; 331 | } 332 | return array('result'=>$jsonDatas); 333 | } 334 | 335 | public function getDailyStat($device, $dayBefore=0) //@device name, @day before 0 1 or 2 | @return['result'] array 336 | { 337 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 338 | if ( isset($device['error']) ) return $device; 339 | 340 | if (!is_int($dayBefore)) return array('error'=> 'Second argument should be 0 1 or 2 for today, yesterday, day before yesterday'); 341 | 342 | $operation = "retrieveDailyStatistics"; 343 | $statSensor = $device['statUID']; 344 | if ($statSensor=='None') return array('result'=>null, 'error'=>"No statistic for such device"); 345 | $answer = $this->invokeOperation($statSensor, $operation, $dayBefore); 346 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 347 | 348 | $jsonDatas = array(); 349 | foreach ($answer['result'] as $item) 350 | { 351 | $sensor = $item['widgetElementUID']; 352 | $values = $item['value']; 353 | if ( isset($item['timeOfDay']) ) $timesOfDay = $item['timeOfDay']; 354 | 355 | if (strstr($device['model'], 'Door/Window:Sensor')) 356 | { 357 | if (strstr($sensor, 'BinarySensor:hdm')) $sensor = 'opened'; 358 | if (strstr($sensor, '#MultilevelSensor(1)')) $sensor = 'temperature'; 359 | if (strstr($sensor, '#MultilevelSensor(3)')) $sensor = 'light'; 360 | } 361 | if (strstr($device['model'], 'Motion:Sensor')) 362 | { 363 | if (strstr($sensor, 'BinarySensor:hdm')) $sensor = 'alarm'; 364 | if (strstr($sensor, '#MultilevelSensor(1)')) $sensor = 'temperature'; 365 | if (strstr($sensor, '#MultilevelSensor(3)')) $sensor = 'light'; 366 | } 367 | 368 | if (strstr($sensor, 'Meter:hdm')) $sensor = 'consumption'; 369 | 370 | $sensorData = array('sensor'=>$sensor); 371 | $countValues = count($values)-1; 372 | for($i=$countValues; $i>=1; $i--) 373 | { 374 | $timeOfDay = gmdate("H:i:s", $timesOfDay[$i]); 375 | $sensorData[$timeOfDay] = $values[$i]; 376 | } 377 | $jsonDatas[] = $sensorData; 378 | } 379 | return array('result'=>$jsonDatas); 380 | } 381 | 382 | public function getWeather() //@return['result'] array of weather data for next three days 383 | { 384 | $jsonString = '{ 385 | "jsonrpc":"2.0", 386 | "method":"FIM/getFunctionalItems", 387 | "params":[ 388 | ["devolo.WeatherWidget"],0 389 | ] 390 | }'; 391 | 392 | $answer = $this->sendCommand($jsonString); 393 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 394 | 395 | $data = $answer['result']['items'][0]['properties']; 396 | 397 | $this->_Weather = array(); 398 | $this->_Weather['currentTemp'] = $data['currentTemp']; 399 | 400 | unset($data['forecastData'][0]['weatherCode'] ); 401 | unset($data['forecastData'][1]['weatherCode'] ); 402 | unset($data['forecastData'][2]['weatherCode'] ); 403 | 404 | $this->_Weather['Today'] = $data['forecastData'][0]; 405 | $this->_Weather['Tomorrow'] = $data['forecastData'][1]; 406 | $this->_Weather['DayAfterT'] = $data['forecastData'][2]; 407 | 408 | $value = $data['lastUpdateTimestamp']; 409 | $this->_Weather['lastUpdate'] = $this->formatStates('LastActivity', 'lastActivityTime', $value); 410 | 411 | return array('result'=>$this->_Weather); 412 | } 413 | 414 | public function getMessageData($msg) //@message name | @return['result'] array of message data 415 | { 416 | if ( is_string($msg) ) $msg = $this->getMessageByName($msg); 417 | if ( isset($msg['error']) ) return $msg; 418 | 419 | $answer = $this->fetchItems(array($msg['element'])); 420 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 421 | return array('result' => $answer['result']['items'][0]['properties']['msgData']); 422 | } 423 | 424 | //______________________CONSUMPTION: 425 | 426 | public function logConsumption($filePath='/') //@log file path | always @return['result'] array of yesterday total consumptions, @return['error'] if can't write file 427 | { 428 | if (@file_exists($filePath)) 429 | { 430 | $prevDatas = json_decode(file_get_contents($filePath), true); 431 | } 432 | else 433 | { 434 | $prevDatas = array(); 435 | } 436 | 437 | //get yesterday sums for each device: 438 | $yesterday = date('d.m.Y',strtotime('-1 days')); 439 | $datasArray = array(); 440 | 441 | foreach ($this->_AllDevices as $device) 442 | { 443 | $sensors = json_decode($device['sensors'], true); 444 | foreach ($sensors as $sensor) 445 | { 446 | if (strstr($sensor, 'Meter:hdm')) 447 | { 448 | $name = $device['name']; 449 | $datas = $this->getDailyStat($device, 1); 450 | $sum = array_sum($datas['result'][0])/1000; 451 | $sum = $sum.'kWh'; 452 | $datasArray[$yesterday][$name] = $sum; 453 | } 454 | } 455 | } 456 | 457 | //add yesterday sums to previously loaded datas: 458 | $prevDatas[$yesterday] = $datasArray[$yesterday]; 459 | 460 | //set recent up: 461 | $keys = array_keys($prevDatas); 462 | usort($keys, array('DevoloDHC','sortByDate')); 463 | $newArray = array(); 464 | foreach ($keys as $key) 465 | { 466 | $newArray[$key] = $prevDatas[$key]; 467 | } 468 | $prevDatas = $newArray; 469 | 470 | //write it to file: 471 | @$put = file_put_contents($filePath, json_encode($prevDatas, JSON_PRETTY_PRINT)); 472 | if ($put) return array('result'=>$datasArray); 473 | return array('result'=>$datasArray, 'error'=>'Unable to write file!'); 474 | } 475 | 476 | public function getLogConsumption($filePath='/', $dateStart=null, $dateEnd=null) //@log file path | @return['result'] array, @return['error'] if can't read file 477 | { 478 | if (file_exists($filePath)) 479 | { 480 | $prevDatas = json_decode(file_get_contents($filePath), true); 481 | $keys = array_keys($prevDatas); 482 | $logDateStart = $keys[0]; 483 | $logDateEnd = $keys[count($prevDatas)-1]; 484 | 485 | if (!isset($dateStart)) $dateStart = $logDateStart; 486 | if (!isset($dateEnd)) $dateEnd = $logDateEnd; 487 | 488 | $sumArray = array(); 489 | $c = count($prevDatas); 490 | for($i=0; $i<$c; $i++) 491 | { 492 | $thisDate = $keys[$i]; 493 | $data = $prevDatas[$thisDate]; 494 | if ( strtotime($thisDate)<=strtotime($dateStart) and strtotime($thisDate)>=strtotime($dateEnd)) 495 | { 496 | foreach ($data as $name => $value) 497 | { 498 | if (!isset($sumArray[$name])) $sumArray[$name] = 0; 499 | $sumArray[$name] += $value; 500 | } 501 | } 502 | } 503 | foreach ($sumArray as $name => $value) 504 | { 505 | $sumArray[$name] = $value.'kWh'; 506 | } 507 | return array('result'=>$sumArray); 508 | } 509 | else 510 | { 511 | return array('result'=>null, 'error'=>'Unable to open file'); 512 | } 513 | } 514 | 515 | //______________________SET: 516 | 517 | public function startScene($scene) //@scene name | @return['result'] central answer, @return['error'] if any 518 | { 519 | if ( is_string($scene) ) $scene = $this->getSceneByName($scene); 520 | if ( isset($scene['error']) ) return $scene; 521 | 522 | $element = $scene['element']; 523 | $answer = $this->invokeOperation($element, "start"); 524 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 525 | $result = ( ($answer['result'] == null) ? true : false ); 526 | return array('result'=>$result); 527 | } 528 | 529 | public function turnRuleOnOff($rule, $state=0) //@rule name | @return['result'] central answer, @return['error'] if any 530 | { 531 | if ( is_string($rule) ) $rule = $this->getRuleByName($rule); 532 | if ( isset($rule['error']) ) return $rule; 533 | 534 | $value = ( ($state == 0) ? 'false' : 'true' ); 535 | 536 | $jsonString = '{ 537 | "jsonrpc":"2.0", 538 | "method":"FIM/setProperty", 539 | "params":["'.$rule['element'].'","enabled",'.$value.']}'; 540 | 541 | $answer = $this->sendCommand($jsonString); 542 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 543 | return array('result'=>$answer); 544 | } 545 | 546 | public function turnTimerOnOff($timer, $state=0) //@timer name | @return['result'] central answer, @return['error'] if any 547 | { 548 | if ( is_string($timer) ) $timer = $this->getTimerByName($timer); 549 | if ( isset($timer['error']) ) return $timer; 550 | 551 | $value = ( ($state == 0) ? 'false' : 'true' ); 552 | 553 | $jsonString = '{ 554 | "jsonrpc":"2.0", 555 | "method":"FIM/setProperty", 556 | "params":["'.$timer['element'].'","enabled",'.$value.']}'; 557 | 558 | $answer = $this->sendCommand($jsonString); 559 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 560 | return array('result'=>$answer); 561 | } 562 | 563 | public function turnDeviceOnOff($device, $state=0, $switch=null) //@device name | @return['result'] central answer, @return['error'] if any 564 | { 565 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 566 | if ( isset($device['error']) ) return $device; 567 | 568 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true) : null); 569 | if ($sensors == null) return array('result'=>null, 'error' => 'No sensor found in this device'); 570 | 571 | if ($state < 0) $state = 0; 572 | if ($state > 1) $state = 1; 573 | 574 | foreach ($sensors as $sensor) 575 | { 576 | $sensorType = $this->getSensorType($sensor); 577 | 578 | if (in_array($sensorType, $this->_SensorsOnOff)) 579 | { 580 | $operation = ($state == 0 ? 'turnOff' : 'turnOn'); 581 | 582 | //check qubino 2 relay: 583 | if ($switch != null) 584 | { 585 | $thisSwitch = substr($sensor, -2); 586 | //several switches detected? 587 | if ($thisSwitch != '#1' and $thisSwitch != '#2') return array('result'=>null, 'error' => 'This switch does not seem to have several contacts'); 588 | //get the other switch: 589 | if ($thisSwitch == '#1') $otherSensor = str_replace('#1', '#2', $sensor); 590 | if ($thisSwitch == '#2') $otherSensor = str_replace('#2', '#1', $sensor); 591 | //so, which swhit(ches) to activate: 592 | if ($switch == 'All') 593 | { 594 | $answer = $this->invokeOperation($sensor, $operation); 595 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 596 | $answer = $this->invokeOperation($otherSensor, $operation); 597 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 598 | return array('result'=>true); 599 | } 600 | if ($switch == 1 and $thisSwitch == '#1') 601 | { 602 | $answer = $this->invokeOperation($sensor, $operation); 603 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 604 | return array('result'=>true); 605 | } 606 | if ($switch == 2 and $thisSwitch == '#2') 607 | { 608 | $answer = $this->invokeOperation($sensor, $operation); 609 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 610 | return array('result'=>true); 611 | } 612 | } 613 | else //single sensor request: 614 | { 615 | $answer = $this->invokeOperation($sensor, $operation); 616 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 617 | return array('result'=>true); 618 | } 619 | } 620 | if (in_array($sensorType, $this->_SensorsSend) and ($state == 1)) 621 | { 622 | $operation = "send"; 623 | $answer = $this->invokeOperation($sensor, $operation); 624 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 625 | return array('result'=>true); 626 | } 627 | } 628 | return array('result'=>null, 'error' => 'No supported sensor for this device'); 629 | } 630 | 631 | public function turnGroupOnOff($group, $state=0) //@group name | @return['result'] central answer, @return['error'] if any 632 | { 633 | if ( is_string($group) ) $group = $this->getGroupByName($group); 634 | if ( isset($group['error']) ) return $group; 635 | 636 | $sensor = 'devolo.BinarySwitch:'.$group['id']; 637 | if ($state < 0) $state = 0; 638 | 639 | $operation = ($state == 0 ? 'turnOff' : 'turnOn'); 640 | $answer = $this->invokeOperation($sensor, $operation); 641 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 642 | return array('result'=>true); 643 | } 644 | 645 | public function setDeviceValue($device, $value) //@device name, @value | @return['result'] central answer, @return['error'] if any 646 | { 647 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 648 | if ( isset($device['error']) ) return $device; 649 | 650 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true) : null); 651 | if ($sensors == null) return array('result'=>null, 'error' => 'No sensor found in this device'); 652 | 653 | foreach ($sensors as $sensor) 654 | { 655 | $sensorType = $this->getSensorType($sensor); 656 | 657 | if (in_array($sensorType, $this->_SensorsSendValue)) 658 | { 659 | $operation = 'sendValue'; 660 | $answer = $this->invokeOperation($sensor, $operation, $value); 661 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 662 | return array('result'=>true); 663 | } 664 | } 665 | return array('result'=>null, 'error' => 'No supported sensor for this device'); 666 | } 667 | 668 | public function pressDeviceKey($device, $key=null) //@device name, @key number | @return['result'] central answer, @return['error'] if any 669 | { 670 | if (!isset($key)) return array('result'=>null, 'error' => 'No defined key to press'); 671 | if ($key > 4) return array('result'=>null, 'error' => 'You really have Wall Switch with more than 4 buttons ? Let me know!'); 672 | 673 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 674 | if ( isset($device['error']) ) return $device; 675 | 676 | $sensors = (isset($device['sensors']) ? json_decode($device['sensors'], true) : null); 677 | if ($sensors == null) return array('result'=>null, 'error' => 'No sensor found in this device'); 678 | 679 | foreach($sensors as $sensor) 680 | { 681 | $sensorType = $this->getSensorType($sensor); 682 | if (in_array($sensorType, $this->_SensorsPressKey)) 683 | { 684 | $operation = 'pressKey'; 685 | $answer = $this->invokeOperation($sensor, $operation, $key); 686 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 687 | return array('result'=>true); 688 | } 689 | } 690 | return array('result'=>null, 'error' => 'No supported sensor for this device'); 691 | } 692 | 693 | public function sendMessage($msg) //@message name | @return['result'] central answer, @return['error'] if any 694 | { 695 | if ( is_string($msg) ) $msg = $this->getMessageByName($msg); 696 | if ( isset($msg['error']) ) return $msg; 697 | 698 | $element = $msg['element']; 699 | $answer = $this->invokeOperation($element, "send"); 700 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 701 | $result = ( ($answer['result'] == null) ? true : false ); 702 | return array('result'=>$result); 703 | } 704 | 705 | public function setDeviceDiary($device, $state=true) //@device name, @state true/false | @return['result'] central answer, @return['error'] if any 706 | { 707 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 708 | if ( isset($device['error']) ) return $device; 709 | 710 | $deviceName = $device['name']; 711 | $deviceIcon = $device['icon']; 712 | $zoneID = $device['zoneId']; 713 | $deviceSetting = 'gds.'.$device['uid']; 714 | $state = var_export($state, true); 715 | 716 | $jsonString = '{"jsonrpc":"2.0", 717 | "method":"FIM/invokeOperation", 718 | "params":["'.$deviceSetting.'","save",[{"name":"'.$deviceName.'","icon":"'.$deviceIcon.'","zoneID":"'.$zoneID.'","eventsEnabled":'.$state.'}]]}'; 719 | 720 | $answer = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 721 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 722 | return $answer; 723 | } 724 | 725 | //INTERNAL FUNCTIONS================================================== 726 | 727 | //______________________GET shorcuts: 728 | public function getDeviceByName($name) 729 | { 730 | foreach($this->_AllDevices as $thisDevice) 731 | { 732 | if ($thisDevice['name'] == $name) return $thisDevice; 733 | } 734 | return array('result'=>null, 'error' => 'Unfound device'); 735 | } 736 | 737 | public function getRuleByName($name) 738 | { 739 | if (count($this->_AllRules) == 0) $this->getRules(); 740 | 741 | foreach($this->_AllRules as $thisRule) 742 | { 743 | if ($thisRule['name'] == $name) return $thisRule; 744 | } 745 | return array('result'=>null, 'error' => 'Unfound rule'); 746 | } 747 | 748 | public function getTimerByName($name) 749 | { 750 | if (count($this->_AllTimers) == 0) $this->getTimers(); 751 | 752 | foreach($this->_AllTimers as $thisTimer) 753 | { 754 | if ($thisTimer['name'] == $name) return $thisTimer; 755 | } 756 | return array('result'=>null, 'error' => 'Unfound timer'); 757 | } 758 | 759 | public function getSceneByName($name) 760 | { 761 | if (count($this->_AllScenes) == 0) $this->getScenes(); 762 | 763 | foreach($this->_AllScenes as $thisScene) 764 | { 765 | if ($thisScene['name'] == $name) return $thisScene; 766 | } 767 | return array('result'=>null, 'error' => 'Unfound scene'); 768 | } 769 | 770 | public function getGroupByName($name) 771 | { 772 | foreach($this->_AllGroups as $thisGroup) 773 | { 774 | if ($thisGroup['name'] == $name) return $thisGroup; 775 | } 776 | return array('result'=>null, 'error' => 'Unfound group'); 777 | } 778 | 779 | public function getMessageByName($name) 780 | { 781 | if (count($this->_AllMessages) == 0) $this->getMessages(); 782 | 783 | foreach($this->_AllMessages['customMessages'] as $thisMsg) 784 | { 785 | if ($thisMsg['name'] == $name) return $thisMsg; 786 | } 787 | return array('result'=>null, 'error' => 'Unfound Message'); 788 | } 789 | 790 | //______________________internal mixture 791 | 792 | protected function getSensorType($sensor) 793 | { 794 | //devolo.BinarySensor:hdm:ZWave:D8F7DDE2/10 -> BinarySensor 795 | $sensorType = explode('devolo.', $sensor); 796 | if (count($sensorType) == 0) return null; 797 | $sensorType = explode(':', $sensorType[1]); 798 | $sensorType = $sensorType[0]; 799 | return $sensorType; 800 | } 801 | 802 | protected function getValuesByType($sensorType) 803 | { 804 | foreach($this->_SensorValuesByType as $type => $param) 805 | { 806 | if ($type == $sensorType) return $param; 807 | } 808 | return null; 809 | } 810 | 811 | public function debugDevice($device) 812 | { 813 | if ( is_string($device) ) $device = $this->getDeviceByName($device); 814 | if ( isset($device['error']) ) return $device; 815 | 816 | $jsonArray = $this->fetchItems(array($device['uid'])); 817 | echo '
Device:
',json_encode($jsonArray, JSON_PRETTY_PRINT),'

'; 818 | 819 | $elements = $jsonArray['result']['items'][0]['properties']['elementUIDs']; 820 | $elementsArray = $this->fetchItems($elements); 821 | echo '
elementUIDs:
',json_encode($elementsArray, JSON_PRETTY_PRINT),'

'; 822 | 823 | $settings = $jsonArray['result']['items'][0]['properties']['settingUIDs']; 824 | $settingsArray = $this->fetchItems($settings); 825 | echo '
settingUIDs:
',json_encode($settingsArray, JSON_PRETTY_PRINT),'

'; 826 | } 827 | 828 | public function resetSessionTimeout() 829 | { 830 | //cookie expire in 30min, anyway Devolo Central send resetSessionTimeout every 10mins 831 | if (!isset($this->_uuid)) 832 | { 833 | //get uuid: 834 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/getFunctionalItemUIDs","params":["(objectClass=com.devolo.fi.page.Dashboard)"]}'; 835 | $answer = $this->sendCommand($jsonString); 836 | if (isset($answer['result'][0]) ) $uuid = $answer['result'][0]; 837 | else return array('error'=> array('message'=>"can't find uuid!")); 838 | $uuid = $answer['result'][0]; 839 | $uuid = explode('devolo.Dashboard.', $uuid)[1]; 840 | $this->_uuid = $uuid; 841 | } 842 | 843 | $jsonString = '{"jsonrpc":"2.0", "method":"FIM/invokeOperation","params":["devolo.UserPrefs.'.$this->_uuid.'","resetSessionTimeout",[]]}'; 844 | $answer = $this->sendCommand($jsonString); 845 | if (isset($answer['error']['message']) ) return array('result'=>null, 'error'=>$answer['error']['message']); 846 | return array('result'=>$answer['result']); 847 | } 848 | 849 | private function sortByDate($a, $b) //Used for consumption logging sorting 850 | { 851 | $t1 = strtotime($a); 852 | $t2 = strtotime($b); 853 | return ($t2 - $t1); 854 | } 855 | 856 | //______________________getter functions 857 | 858 | protected function getDevices() //First call after connection, ask all zones and register all devices into $this->_AllDevices 859 | { 860 | if (count($this->_AllZones) == 0) 861 | { 862 | $result = $this->getZones(); 863 | if (isset($result['error'])) return $result; 864 | } 865 | 866 | //get all devices from all zones: 867 | $UIDSarray = array(); 868 | foreach ($this->_AllZones as $thisZone) 869 | { 870 | $thisDevices = $thisZone['deviceUIDs']; 871 | foreach ($thisDevices as $thisDevice) 872 | { 873 | $UIDSarray[] = $thisDevice; 874 | } 875 | } 876 | 877 | //request all infos for all devices at once: 878 | $jsonArray = $this->fetchItems($UIDSarray); 879 | 880 | //store devices: 881 | $devices = array(); 882 | foreach ($jsonArray['result']["items"] as $thisDevice) 883 | { 884 | $name = (isset($thisDevice['properties']['itemName']) ? $thisDevice['properties']['itemName'] : 'None'); 885 | $uid = (isset($thisDevice['UID']) ? $thisDevice['UID'] : 'None'); 886 | $elementUIDs = (isset($thisDevice['properties']['elementUIDs']) ? $thisDevice['properties']['elementUIDs'] : 'None'); 887 | 888 | $device = array('name' => $name, 889 | 'uid' => $uid, 890 | 'sensors' => json_encode($elementUIDs), 891 | 'zoneId' => (isset($thisDevice['properties']['zoneId']) ? $thisDevice['properties']['zoneId'] : 'None'), 892 | 'statUID' => (isset($thisDevice['properties']['statisticsUID']) ? $thisDevice['properties']['statisticsUID'] : 'None'), 893 | 'batteryLevel' => (isset($thisDevice['properties']['batteryLevel']) ? $thisDevice['properties']['batteryLevel'] : 'None'), 894 | 'model' => (isset($thisDevice['properties']['deviceModelUID']) ? $thisDevice['properties']['deviceModelUID'] : 'None'), 895 | 'icon' => (isset($thisDevice['properties']['icon']) ? $thisDevice['properties']['icon'] : 'None') 896 | ); 897 | $devices[] = $device; 898 | } 899 | $this->_AllDevices = $devices; 900 | } 901 | 902 | protected function getZones() //called by getDevices(), register all zones into $this->_AllZones and groups into $this->_AllGroups 903 | { 904 | $this->_AllZones = array(); 905 | $this->_AllGroups = array(); 906 | 907 | $jsonString = '{ 908 | "jsonrpc":"2.0", 909 | "method":"FIM/getFunctionalItems", 910 | "params":[ 911 | ["devolo.Grouping"],0 912 | ] 913 | }'; 914 | 915 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 916 | $jsonArray = json_decode($data, true); 917 | 918 | //avoid account with just demo gateway: 919 | if (!isset($jsonArray['result']["items"][0]['properties']['zones'])) 920 | { 921 | $this->error = 'Seems a demo Gateway, or no zones ?'; 922 | return array('result'=>null, 'error'=>$this->error); 923 | } 924 | 925 | //get all zones: 926 | $zones = $jsonArray['result']["items"][0]['properties']['zones']; 927 | foreach ($zones as $thisZone) 928 | { 929 | $thisID = $thisZone['id']; 930 | $thisName = $thisZone['name']; 931 | $thisDevices = $thisZone['deviceUIDs']; 932 | 933 | $zone = array('name' => $thisName, 934 | 'id' => $thisID, 935 | 'deviceUIDs' => $thisDevices 936 | ); 937 | $this->_AllZones[] = $zone; 938 | } 939 | 940 | //get each group infos: 941 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['smartGroupWidgetUIDs']); 942 | 943 | foreach ($jsonArray['result']['items'] as $thisGroup) 944 | { 945 | $thisID = $thisGroup['UID']; 946 | $thisName = $thisGroup['properties']['itemName']; 947 | $thisOurOfSync = $thisGroup['properties']['outOfSync']; 948 | $thisSync = $thisGroup['properties']['synchronized']; 949 | $thisDevices = $thisGroup['properties']['deviceUIDs']; 950 | 951 | $group = array('name' => $thisName, 952 | 'id' => $thisID, 953 | 'outOfSync' => $thisOurOfSync, 954 | 'synchronized' => $thisSync, 955 | 'deviceUIDs' => $thisDevices 956 | ); 957 | $this->_AllGroups[] = $group; 958 | } 959 | } 960 | 961 | protected function getScenes() //called if necessary, register all scenes into $this->_AllScenes 962 | { 963 | $this->_AllScenes = array(); 964 | 965 | $jsonString = '{ 966 | "jsonrpc":"2.0", 967 | "method":"FIM/getFunctionalItems", 968 | "params":[ 969 | ["devolo.Scene"],0 970 | ] 971 | }'; 972 | 973 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 974 | $jsonArray = json_decode($data, true); 975 | 976 | //request datas for all scenes: 977 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['sceneUIDs']); 978 | 979 | foreach($jsonArray['result']['items'] as $thisScene) 980 | { 981 | $scene = array('name' => $thisScene['properties']['itemName'], 982 | 'id' => $thisScene['UID'], 983 | 'element' => str_replace('Scene', 'SceneControl', $thisScene['UID']) 984 | ); 985 | array_push($this->_AllScenes, $scene); 986 | } 987 | } 988 | 989 | protected function getTimers() //called if necessary, register all timers into $this->_AllTimers 990 | { 991 | $this->_AllTimers = array(); 992 | 993 | $jsonString = '{ 994 | "jsonrpc":"2.0", 995 | "method":"FIM/getFunctionalItems", 996 | "params":[ 997 | ["devolo.Schedules"],0 998 | ] 999 | }'; 1000 | 1001 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1002 | $jsonArray = json_decode($data, true); 1003 | 1004 | //request datas for all rules: 1005 | if (isset($jsonArray['result'])) 1006 | { 1007 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['scheduleUIDs']); 1008 | foreach($jsonArray['result']['items'] as $thisTimer) 1009 | { 1010 | $rule = array('name' => $thisTimer['properties']['itemName'], 1011 | 'id' => $thisTimer['UID'], 1012 | 'element' => str_replace('Schedule', 'ScheduleControl', $thisTimer['UID']) 1013 | ); 1014 | array_push($this->_AllTimers, $rule); 1015 | } 1016 | } 1017 | else 1018 | { 1019 | return array('result'=>nul, 'error'=>'Could not get timers'); 1020 | } 1021 | } 1022 | 1023 | protected function getRules() //called if necessary, register all rules into $this->_AllRules 1024 | { 1025 | $this->_AllRules = array(); 1026 | 1027 | $jsonString = '{ 1028 | "jsonrpc":"2.0", 1029 | "method":"FIM/getFunctionalItems", 1030 | "params":[ 1031 | ["devolo.Services"],0 1032 | ] 1033 | }'; 1034 | 1035 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1036 | $jsonArray = json_decode($data, true); 1037 | 1038 | //request datas for all rules: 1039 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['serviceUIDs']); 1040 | 1041 | foreach($jsonArray['result']['items'] as $thisRule) 1042 | { 1043 | $rule = array('name' => $thisRule['properties']['itemName'], 1044 | 'id' => $thisRule['UID'], 1045 | 'element' => str_replace('Service', 'ServiceControl', $thisRule['UID']) 1046 | ); 1047 | array_push($this->_AllRules, $rule); 1048 | } 1049 | } 1050 | 1051 | protected function getMessages() //called if necessary, register all messages into $this->_AllMessages 1052 | { 1053 | $this->_AllMessages = array(); 1054 | 1055 | $jsonString = '{ 1056 | "jsonrpc":"2.0", 1057 | "method":"FIM/getFunctionalItems", 1058 | "params":[ 1059 | ["devolo.Messages"],0 1060 | ] 1061 | }'; 1062 | 1063 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1064 | $jsonArray = json_decode($data, true); 1065 | 1066 | $this->_AllMessages['pnEndpoints'] = $jsonArray['result']['items'][0]['properties']['pnEndpoints']; 1067 | $this->_AllMessages['phoneNumbers'] = $jsonArray['result']['items'][0]['properties']['phoneNumbers']; 1068 | $this->_AllMessages['emailExt'] = $jsonArray['result']['items'][0]['properties']['emailExt']; 1069 | $this->_AllMessages['emailAddresses'] = $jsonArray['result']['items'][0]['properties']['emailAddresses']; 1070 | 1071 | //fetch custom Messages: 1072 | $jsonArray = $this->fetchItems($jsonArray['result']['items'][0]['properties']['customMessageUIDs']); 1073 | 1074 | $this->_AllMessages['customMessages'] = array(); 1075 | foreach($jsonArray['result']['items'] as $thisMsg) 1076 | { 1077 | $msg = array('name' => $thisMsg['properties']['itemName'], 1078 | 'id' => $thisMsg['UID'], 1079 | 'description' => $thisMsg['properties']['description'], 1080 | 'base' => $thisMsg['properties']['base'], 1081 | 'element' => $thisMsg['properties']['elementUIDs'][0] 1082 | ); 1083 | array_push($this->_AllMessages['customMessages'], $msg); 1084 | } 1085 | } 1086 | 1087 | protected function formatStates($sensorType, $key, $value) //string formating accordingly to type of data. May support units regarding timezone in the future... 1088 | { 1089 | if ($sensorType=='Meter' and $key=='totalValue') return $value.'kWh'; 1090 | if ($sensorType=='Meter' and $key=='currentValue') return $value.'W'; 1091 | if ($sensorType=='Meter' and $key=='voltage') return $value.'V'; 1092 | if ($key=='sinceTime') 1093 | { 1094 | $ts = $value; 1095 | $ts = substr($ts, 0, -3) - 3600; //microtime timestamp from Berlin 1096 | $date = new DateTime(); 1097 | $date->setTimestamp($ts); 1098 | $date->setTimezone(new DateTimeZone(date_default_timezone_get())); //set it to php server timezone 1099 | $date = $date->format('d.m.Y H:i'); 1100 | return $date; 1101 | } 1102 | if ($sensorType=='LastActivity' and $key=='lastActivityTime') 1103 | { 1104 | if ($value == -1) return 'Never'; 1105 | //convert javascript timestamp to date: 1106 | $ts = $value; 1107 | $ts = substr($ts, 0, -3) - 3600; //microtime timestamp from Berlin 1108 | $date = new DateTime(); 1109 | $date->setTimestamp($ts); 1110 | $date->setTimezone(new DateTimeZone(date_default_timezone_get())); //set it to php server timezone 1111 | 1112 | //format it: 1113 | $nowDate = new DateTime(); 1114 | $interval = $nowDate->diff($date)->days; 1115 | switch($interval) { 1116 | case 0: 1117 | $date = 'Today '.$date->format('H:i'); 1118 | break; 1119 | case -1: 1120 | $date = 'Yesterday '.$date->format('H:i'); 1121 | break; 1122 | default: 1123 | $date = $date->format('d.m.Y H:i'); 1124 | } 1125 | return $date; 1126 | } 1127 | return $value; 1128 | } 1129 | 1130 | 1131 | //______________________calling functions 1132 | 1133 | protected function _request($method, $host, $path, $jsonString=null, $postinfo=null) //standard function handling all get/post request with curl | return string 1134 | { 1135 | if (!isset($this->_curlHdl)) 1136 | { 1137 | $this->_curlHdl = curl_init(); 1138 | curl_setopt($this->_curlHdl, CURLOPT_URL, $this->_authUrl); 1139 | 1140 | curl_setopt($this->_curlHdl, CURLOPT_COOKIEJAR, $this->_cookFile); 1141 | curl_setopt($this->_curlHdl, CURLOPT_COOKIEFILE, $this->_cookFile); 1142 | 1143 | curl_setopt($this->_curlHdl, CURLOPT_SSL_VERIFYHOST, false); 1144 | curl_setopt($this->_curlHdl, CURLOPT_SSL_VERIFYPEER, false); 1145 | 1146 | curl_setopt($this->_curlHdl, CURLOPT_RETURNTRANSFER, true); 1147 | curl_setopt($this->_curlHdl, CURLOPT_FOLLOWLOCATION, true); 1148 | 1149 | curl_setopt($this->_curlHdl, CURLOPT_REFERER, 'http://www.google.com/'); 1150 | curl_setopt($this->_curlHdl, CURLOPT_USERAGENT, 'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0'); 1151 | 1152 | curl_setopt($this->_curlHdl, CURLOPT_ENCODING , "gzip"); 1153 | } 1154 | 1155 | $url = filter_var($host.$path, FILTER_SANITIZE_URL); 1156 | 1157 | curl_setopt($this->_curlHdl, CURLOPT_URL, $url); 1158 | 1159 | if ($method == 'POST') 1160 | { 1161 | curl_setopt($this->_curlHdl, CURLOPT_RETURNTRANSFER, true); 1162 | curl_setopt($this->_curlHdl, CURLOPT_POST, true); 1163 | } 1164 | else 1165 | { 1166 | curl_setopt($this->_curlHdl, CURLOPT_POST, false); 1167 | } 1168 | 1169 | if ( isset($jsonString) ) 1170 | { 1171 | $jsonString = str_replace('"jsonrpc":"2.0",', '"jsonrpc":"2.0", "id":'.$this->_POSTid.',', $jsonString); 1172 | $this->_POSTid++; 1173 | curl_setopt($this->_curlHdl, CURLOPT_HEADER, false); 1174 | curl_setopt($this->_curlHdl, CURLINFO_HEADER_OUT, false ); 1175 | curl_setopt($this->_curlHdl, CURLOPT_POST, false); 1176 | curl_setopt($this->_curlHdl, CURLOPT_CUSTOMREQUEST, 'POST'); 1177 | curl_setopt($this->_curlHdl, CURLOPT_POSTFIELDS, $jsonString); 1178 | } 1179 | 1180 | if ( isset($postinfo) ) 1181 | { 1182 | curl_setopt($this->_curlHdl, CURLOPT_POSTFIELDS, $postinfo); 1183 | } 1184 | 1185 | $response = curl_exec($this->_curlHdl); 1186 | 1187 | //$info = curl_getinfo($this->_curlHdl); 1188 | //echo "
cURL info".json_encode($info, JSON_PRETTY_PRINT)."

"; 1189 | 1190 | $this->error = null; 1191 | if ($response === false) $this->error = curl_error($this->_curlHdl); 1192 | return $response; 1193 | } 1194 | 1195 | protected function fetchItems($UIDSarray) //get infos from central for array of device, sensor, timer etc | return array 1196 | { 1197 | $devicesJson = json_encode($UIDSarray); 1198 | $jsonString = '{ 1199 | "jsonrpc":"2.0", 1200 | "method":"FIM/getFunctionalItems", 1201 | "params":[ 1202 | '.$devicesJson.',0 1203 | ] 1204 | }'; 1205 | 1206 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1207 | $jsonArray = json_decode($data, true); 1208 | return $jsonArray; 1209 | } 1210 | 1211 | protected function invokeOperation($sensor, $operation, $value=null) //sensor string, authorized operation string | return array 1212 | { 1213 | $value = '['.$value.']'; 1214 | $jsonString = '{ 1215 | "jsonrpc":"2.0", 1216 | "method":"FIM/invokeOperation", 1217 | "params":["'.$sensor.'","'.$operation.'",'.$value.']}'; 1218 | 1219 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1220 | $jsonArray = json_decode($data, true); 1221 | return $jsonArray; 1222 | } 1223 | 1224 | public function sendCommand($jsonString) //directly send json to central. Only works when all required authorisations are set | return array 1225 | { 1226 | $data = $this->_request('POST', $this->_dhcUrl, '/remote/json-rpc', $jsonString); 1227 | $jsonArray = json_decode($data, true); 1228 | return $jsonArray; 1229 | } 1230 | 1231 | //______________________Internal cooking 1232 | 1233 | //user central stuff: 1234 | public $error = null; 1235 | public $_userInfos; 1236 | public $_centralInfos; 1237 | public $_gateway; 1238 | public $_gateIdx = 0; 1239 | public $_uuid = null; 1240 | public $_token; 1241 | public $_wasCookiesLoaded = false; 1242 | public $_cookFile = ''; 1243 | 1244 | //central stuff stuff(!): 1245 | public $_AllDevices = null; 1246 | public $_AllZones = null; 1247 | public $_AllGroups = null; 1248 | public $_AllRules = null; 1249 | public $_AllTimers = null; 1250 | public $_AllScenes = null; 1251 | public $_AllMessages = null; 1252 | public $_Weather = null; 1253 | 1254 | //authentication: 1255 | protected $_login; 1256 | protected $_password; 1257 | protected $_authUrl = 'https://www.mydevolo.com'; 1258 | protected $_dhcUrl = 'https://homecontrol.mydevolo.com'; 1259 | protected $_lang = '/en'; 1260 | protected $_POSTid = 0; 1261 | protected $_curlHdl = null; 1262 | 1263 | //types stuff: 1264 | /* 1265 | Devolo Home Control Portal (web interface or app interface to access HCB Home Control Box) 1266 | -> HCB 1267 | ->Device 1268 | - sensor (type, data), handle operations ? 1269 | - sensor (type, data), handle operations ? 1270 | ->Zone 1271 | - deviceUIDs 1272 | ->Group 1273 | - deviceUIDs 1274 | etc 1275 | */ 1276 | 1277 | /* UNTESTED: 1278 | devolo.model.Dimmer / Dimmer 1279 | devolo.model.Relay / Relay 1280 | HueBulbSwitch / HueBulbSwitch 1281 | HueBulbColor / HueBulbColor 1282 | */ 1283 | //Sensors Operations: 1284 | protected $_SensorsOnOff = array('BinarySwitch', 'BinarySensor', 'HueBulbSwitch', 'Relay'); //supported sensor types for 'turnOn'/'turnOff' operation 1285 | protected $_SensorsSendValue = array('MultiLevelSwitch', 'SirenMultiLevelSwitch', 'Blinds', 'Dimmer'); //supported sensor types for 'sendValue' operation 1286 | protected $_SensorsPressKey = array('RemoteControl'); //supported sensor types for 'pressKey' operation 1287 | protected $_SensorsSendHSB = array('HueBulbColor'); //supported sensor types for 'sendHSB' operation 1288 | protected $_SensorsSend = array('HttpRequest'); //supported sensor types for 'send' operation 1289 | protected $_SensorsNoValues = array('HttpRequest'); //virtual device sensor 1290 | //Sensors Values: 1291 | protected $_SensorValuesByType = array( 1292 | 'Meter' => array('sensorType', 'currentValue', 'totalValue', 'sinceTime'), 1293 | 'BinarySwitch' => array('switchType', 'state', 'targetState'), 1294 | 'Relay' => array('switchType', 'state', 'targetState'), 1295 | 'MildewSensor' => array('sensorType', 'state'), 1296 | 'BinarySensor' => array('sensorType', 'state'), 1297 | 'SirenBinarySensor' => array('sensorType', 'state'), 1298 | 'MultiLevelSensor' => array('sensorType', 'value'), 1299 | 'HumidityBarZone' => array('sensorType', 'value'), 1300 | 'DewpointSensor' => array('sensorType', 'value'), 1301 | 'HumidityBarValue' => array('sensorType', 'value'), 1302 | 'SirenMultiLevelSensor' => array('sensorType', 'value'), 1303 | 'SirenMultiLevelSwitch' => array('switchType', 'value', 'targetValue', 'min', 'max'), 1304 | 'MultiLevelSwitch' => array('switchType', 'value', 'targetValue', 'min', 'max'), 1305 | 'RemoteControl' => array('keyCount', 'keyPressed'), 1306 | 'Blinds' => array('switchType', 'value', 'targetValue', 'min', 'max'), 1307 | 'Dimmer' => array('switchType', 'value', 'targetValue', 'min', 'max'), 1308 | 'HueBulbSwitch' => array('sensorType', 'state'), 1309 | 'HueBulbColor' => array('switchType', 'hue', 'sat', 'bri', 'targetHsb'), 1310 | 'LastActivity' => array('lastActivityTime'), 1311 | 'WarningBinaryFI' => array('sensorType', 'state', 'type'), 1312 | 'VoltageMultiLevelSensor' => array('sensorType', 'value' ) 1313 | ); 1314 | 1315 | //functions authorization============================================= 1316 | protected function getCSRF($htmlString) 1317 | { 1318 | $dom = new DOMDocument(); 1319 | @$dom->loadHTML($htmlString); 1320 | $nodes = $dom->getElementsByTagName('input'); 1321 | foreach($nodes as $node) 1322 | { 1323 | if ($node->hasAttributes()) 1324 | { 1325 | foreach($node->attributes as $attribute) 1326 | { 1327 | if ($attribute->nodeName == 'type' && $attribute->nodeValue == 'hidden') 1328 | { 1329 | $name = $node->getAttribute('name'); 1330 | if (stripos($name, 'csrf') !== false) return $node->getAttribute('value'); 1331 | } 1332 | } 1333 | } 1334 | } 1335 | return False; 1336 | } 1337 | 1338 | protected function cookies_are_hot() 1339 | { 1340 | if ( is_writable(__DIR__) ) //API can write in his folder 1341 | { 1342 | $this->_cookFile = __DIR__.'/dhc_cookies.txt'; 1343 | 1344 | if ( is_writable($this->_cookFile) and (time()-filemtime($this->_cookFile) < 1500) ) //cookie file exist and is younger than 25mins 1345 | { 1346 | //return true; //no check is 0.15s faster! 1347 | $var = file_get_contents($this->_cookFile); 1348 | if (strstr($var, 'JSESSIONID')) 1349 | { 1350 | $answer = $this->resetSessionTimeout(); 1351 | if ( !isset($answer['error']['message']) ) 1352 | { 1353 | $this->_wasCookiesLoaded = true; 1354 | return true; 1355 | } 1356 | else 1357 | { 1358 | curl_close($this->_curlHdl); //was initialized by resetSessionTimeout and will keep old cookies file! 1359 | $this->_curlHdl = null; 1360 | @unlink($this->_cookFile); 1361 | return false; 1362 | } 1363 | } 1364 | } 1365 | if ( is_writable($this->_cookFile) ) unlink($this->_cookFile); 1366 | } 1367 | else 1368 | { 1369 | $this->_wasCookiesLoaded = 'Unable to write cookies file'; 1370 | return false; 1371 | } 1372 | return false; 1373 | } 1374 | 1375 | protected function auth() 1376 | { 1377 | if ($this->cookies_are_hot()) return true; 1378 | //No young cookie file, full authentication: 1379 | 1380 | //___________get CSRF_______________________________________________________ 1381 | $response = $this->_request('GET', $this->_authUrl, $this->_lang, null); 1382 | 1383 | if($response==false) 1384 | { 1385 | $this->error = "Can't connect to Devolo servers."; 1386 | return false; 1387 | } 1388 | 1389 | $csrf = $this->getCSRF($response); 1390 | if ($csrf != false) 1391 | { 1392 | $this->_csrf = $csrf; 1393 | } 1394 | else 1395 | { 1396 | $this->error = "Couldn't find Devolo CSRF."; 1397 | return false; 1398 | } 1399 | 1400 | 1401 | //___________post login/password____________________________________________ 1402 | $postinfo = '_csrf='.$csrf.'&username='.$this->_login.'&password='.$this->_password; 1403 | $response = $this->_request('POST', $this->_authUrl, $this->_lang, null, $postinfo); 1404 | 1405 | 1406 | //___________get gateway____________________________________________________ 1407 | $path = $this->_lang.'/hc/gateways/status'; 1408 | $response = $this->_request('GET', $this->_authUrl, $path, null); 1409 | $json = json_decode($response, true); 1410 | 1411 | if (isset($json['data'][$this->_gateIdx]['id'])) 1412 | { 1413 | $gateway = $json['data'][$this->_gateIdx]['id']; 1414 | $this->_gateway = $gateway; 1415 | } 1416 | else 1417 | { 1418 | $this->error = "Couldn't find Devolo gateway."; 1419 | return false; 1420 | } 1421 | 1422 | //___________get open Gateway_______________________________________________ 1423 | $path = $this->_lang.'/hc/gateways/'.$gateway.'/open'; 1424 | $response = $this->_request('GET', $this->_authUrl, $path, null, null); 1425 | 1426 | return true; 1427 | } 1428 | 1429 | function __construct($login, $password, $connect=true, $gateIdx=0) 1430 | { 1431 | $this->_login = urlencode($login); 1432 | $this->_password = urlencode($password); 1433 | $this->_gateIdx = $gateIdx; 1434 | 1435 | if ($connect==true) 1436 | { 1437 | if ($this->auth() == true) $this->getDevices(); 1438 | } 1439 | } 1440 | 1441 | /* 1442 | dynamic call to getAllxxx / $_DHC->getAllDevices(); 1443 | if _AllDevices is null, call getDevices, return _AllDevices 1444 | 1445 | getAllDevices() / getAllZones() / getAllGroups() / getAllRules() / getAllTimers() / getAllScenes() / getAllMessages() 1446 | */ 1447 | public function __call($name, $args) 1448 | { 1449 | if (preg_match('/^get(.+)/', $name, $matches)) 1450 | { 1451 | $var_name = '_'.$matches[1]; 1452 | $fn_name = substr($var_name, 4); 1453 | 1454 | if (@count($this->$var_name) == 0) 1455 | { 1456 | $this->$var_name = 'Undefined'; 1457 | call_user_func(array($this, 'get'.$fn_name)); 1458 | } 1459 | //unknown var/function: 1460 | return array('result'=>$this->$var_name); 1461 | } 1462 | //no get, no function! 1463 | return array('result'=>null, 'error'=>'Undefined function'); 1464 | } 1465 | 1466 | //DevoloDHC end 1467 | } 1468 | 1469 | ?> 1470 | --------------------------------------------------------------------------------