├── 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 |
42 |
43 |
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 |
--------------------------------------------------------------------------------