iobroker.panasonic-comfort-cloud 1.2.6 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +43 -72
- package/build/lib/tools.js +6 -5
- package/build/main.js +154 -106
- package/io-package.json +61 -5
- package/package.json +6 -8
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
- package/iob_npm.done +0 -1
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2021 marc <marc@lammers.dev>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -12,85 +12,56 @@
|
|
|
12
12
|
|
|
13
13
|
## panasonic-comfort-cloud adapter for ioBroker
|
|
14
14
|
|
|
15
|
-
Adapter
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
You are almost done, only a few steps left:
|
|
23
|
-
1. Create a new repository on GitHub with the name `ioBroker.panasonic-comfort-cloud`
|
|
24
|
-
1. Initialize the current folder as a new git repository:
|
|
25
|
-
```bash
|
|
26
|
-
git init
|
|
27
|
-
git add .
|
|
28
|
-
git commit -m "Initial commit"
|
|
29
|
-
```
|
|
30
|
-
1. Link your local repository with the one on GitHub:
|
|
31
|
-
```bash
|
|
32
|
-
git remote add origin https://github.com/marc2016/ioBroker.panasonic-comfort-cloud
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
1. Push all files to the GitHub repo:
|
|
36
|
-
```bash
|
|
37
|
-
git push origin master
|
|
38
|
-
```
|
|
39
|
-
1. Head over to [src/main.ts](src/main.ts) and start programming!
|
|
40
|
-
|
|
41
|
-
### Scripts in `package.json`
|
|
42
|
-
Several npm scripts are predefined for your convenience. You can run them using `npm run <scriptname>`
|
|
43
|
-
| Script name | Description |
|
|
44
|
-
|-------------|----------------------------------------------------------|
|
|
45
|
-
| `build` | Re-compile the TypeScript sources. |
|
|
46
|
-
| `watch` | Re-compile the TypeScript sources and watch for changes. |
|
|
47
|
-
| `test:ts` | Executes the tests you defined in `*.test.ts` files. |
|
|
48
|
-
| `test:package` | Ensures your `package.json` and `io-package.json` are valid. |
|
|
49
|
-
| `test:unit` | Tests the adapter startup with unit tests (fast, but might require module mocks to work). |
|
|
50
|
-
| `test:integration`| Tests the adapter startup with an actual instance of ioBroker. |
|
|
51
|
-
| `test` | Performs a minimal test run on package files and your tests. |
|
|
52
|
-
| `coverage` | Generates code coverage using your test files. |
|
|
53
|
-
|
|
54
|
-
### Writing tests
|
|
55
|
-
When done right, testing code is invaluable, because it gives you the
|
|
56
|
-
confidence to change your code while knowing exactly if and when
|
|
57
|
-
something breaks. A good read on the topic of test-driven development
|
|
58
|
-
is https://hackernoon.com/introduction-to-test-driven-development-tdd-61a13bc92d92.
|
|
59
|
-
Although writing tests before the code might seem strange at first, but it has very
|
|
60
|
-
clear upsides.
|
|
61
|
-
|
|
62
|
-
The template provides you with basic tests for the adapter startup and package files.
|
|
63
|
-
It is recommended that you add your own tests into the mix.
|
|
64
|
-
|
|
65
|
-
### Publishing the adapter
|
|
66
|
-
See the documentation of [ioBroker.repositories](https://github.com/ioBroker/ioBroker.repositories#requirements-for-adapter-to-get-added-to-the-latest-repository).
|
|
67
|
-
|
|
68
|
-
### Test the adapter manually on a local ioBroker installation
|
|
69
|
-
In order to install the adapter locally without publishing, the following steps are recommended:
|
|
70
|
-
1. Create a tarball from your dev directory:
|
|
71
|
-
```bash
|
|
72
|
-
npm pack
|
|
73
|
-
```
|
|
74
|
-
1. Upload the resulting file to your ioBroker host
|
|
75
|
-
1. Install it locally (The paths are different on Windows):
|
|
76
|
-
```bash
|
|
77
|
-
cd /opt/iobroker
|
|
78
|
-
npm i /path/to/tarball.tgz
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
For later updates, the above procedure is not necessary. Just do the following:
|
|
82
|
-
1. Overwrite the changed files in the adapter directory (`/opt/iobroker/node_modules/iobroker.panasonic-comfort-cloud`)
|
|
83
|
-
1. Execute `iobroker upload panasonic-comfort-cloud` on the ioBroker host
|
|
15
|
+
Adapter to control devices in the Panasonic Comfort Cloud. It uses REST calls which are extracetd from the official Comfort Cloud app.
|
|
16
|
+
To use the a adpter you need to enter your username and password in the configuration. They are used to authenticate access to the Comfort Cloud. Information of all devices is automatically retrieved and inserted as an object. The adpter polls the device information cyclically (see interval in the settings) and sends commands directly to the cloud.
|
|
17
|
+
|
|
18
|
+
With the method used, only one client can be logged on with the account at a time.
|
|
19
|
+
It is recommended that a second account, for which the devices have been shared, is used.
|
|
20
|
+
|
|
84
21
|
|
|
85
22
|
## Changelog
|
|
86
23
|
|
|
87
|
-
### 0.0
|
|
88
|
-
*
|
|
24
|
+
### 2.0.0
|
|
25
|
+
* Added js-controller 3 dependency.
|
|
26
|
+
* Added username and password to protectedNative and password to encryptedNative.
|
|
27
|
+
* Added connection info.
|
|
28
|
+
* Changed schdule to timeout for refresh.
|
|
29
|
+
* Fixes for async await pattern.
|
|
30
|
+
|
|
31
|
+
### 1.2.9
|
|
32
|
+
* Error handling for get device added.
|
|
33
|
+
|
|
34
|
+
### 1.2.8
|
|
35
|
+
* Fixed bug in Comfort Cloud client.
|
|
36
|
+
|
|
37
|
+
### 1.2.7
|
|
38
|
+
* Comfort Cloud client updated.
|
|
39
|
+
|
|
40
|
+
### 1.2.6
|
|
41
|
+
* Fixed bug that guid is null in device creation.
|
|
42
|
+
|
|
43
|
+
### 1.2.5
|
|
44
|
+
* *Comfort Cloud client updated.
|
|
45
|
+
|
|
46
|
+
### 1.2.4
|
|
47
|
+
* Fixed bug with undefined guid. Log messages added.
|
|
48
|
+
|
|
49
|
+
### 1.2.3
|
|
50
|
+
* Set parameters only for writable states.
|
|
51
|
+
|
|
52
|
+
### 1.2.2
|
|
53
|
+
* *Fixed error handling and added stack info.
|
|
54
|
+
|
|
55
|
+
### 1.2.1
|
|
56
|
+
* Fixed bug in refesh device method.
|
|
57
|
+
|
|
58
|
+
### 1.2.0
|
|
59
|
+
* States insideTemperature, outTemperature and Nanoe added.
|
|
89
60
|
|
|
90
61
|
## License
|
|
91
62
|
MIT License
|
|
92
63
|
|
|
93
|
-
Copyright (c)
|
|
64
|
+
Copyright (c) 2021 marc <marc@lammers.dev>
|
|
94
65
|
|
|
95
66
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
96
67
|
of this software and associated documentation files (the "Software"), to deal
|
package/build/lib/tools.js
CHANGED
|
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.translateText = exports.isArray = exports.isObject = void 0;
|
|
12
13
|
const axios_1 = require("axios");
|
|
13
14
|
/**
|
|
14
15
|
* Tests whether the given variable is a real object and not an Array
|
|
@@ -19,7 +20,7 @@ function isObject(it) {
|
|
|
19
20
|
// typeof null === 'object'
|
|
20
21
|
// typeof [] === 'object'
|
|
21
22
|
// [] instanceof Object === true
|
|
22
|
-
return Object.prototype.toString.call(it) ===
|
|
23
|
+
return Object.prototype.toString.call(it) === '[object Object]';
|
|
23
24
|
}
|
|
24
25
|
exports.isObject = isObject;
|
|
25
26
|
/**
|
|
@@ -29,7 +30,7 @@ exports.isObject = isObject;
|
|
|
29
30
|
function isArray(it) {
|
|
30
31
|
if (Array.isArray != null)
|
|
31
32
|
return Array.isArray(it);
|
|
32
|
-
return Object.prototype.toString.call(it) ===
|
|
33
|
+
return Object.prototype.toString.call(it) === '[object Array]';
|
|
33
34
|
}
|
|
34
35
|
exports.isArray = isArray;
|
|
35
36
|
/**
|
|
@@ -39,16 +40,16 @@ exports.isArray = isArray;
|
|
|
39
40
|
*/
|
|
40
41
|
function translateText(text, targetLang) {
|
|
41
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
-
if (targetLang ===
|
|
43
|
+
if (targetLang === 'en')
|
|
43
44
|
return text;
|
|
44
45
|
try {
|
|
45
46
|
const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`;
|
|
46
|
-
const response = yield axios_1.default({ url, timeout: 5000 });
|
|
47
|
+
const response = yield (0, axios_1.default)({ url, timeout: 5000 });
|
|
47
48
|
if (isArray(response.data)) {
|
|
48
49
|
// we got a valid response
|
|
49
50
|
return response.data[0][0][0];
|
|
50
51
|
}
|
|
51
|
-
throw new Error(
|
|
52
|
+
throw new Error('Invalid response for translate request');
|
|
52
53
|
}
|
|
53
54
|
catch (e) {
|
|
54
55
|
throw new Error(`Could not translate to "${targetLang}": ${e}`);
|
package/build/main.js
CHANGED
|
@@ -16,67 +16,77 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
16
16
|
// you need to create an adapter
|
|
17
17
|
const utils = require("@iobroker/adapter-core");
|
|
18
18
|
const panasonic_comfort_cloud_client_1 = require("panasonic-comfort-cloud-client");
|
|
19
|
-
const node_schedule_1 = require("node-schedule");
|
|
20
19
|
const _ = require("lodash");
|
|
20
|
+
const REFRESH_INTERVAL_IN_MINUTES_DEFAULT = 5;
|
|
21
21
|
const comfortCloudClient = new panasonic_comfort_cloud_client_1.ComfortCloudClient();
|
|
22
22
|
class PanasonicComfortCloud extends utils.Adapter {
|
|
23
23
|
constructor(options = {}) {
|
|
24
|
-
super(Object.assign(Object.assign({}, options), { name:
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
27
|
-
this.on(
|
|
24
|
+
super(Object.assign(Object.assign({}, options), { name: 'panasonic-comfort-cloud' }));
|
|
25
|
+
this.refreshIntervalInMinutes = REFRESH_INTERVAL_IN_MINUTES_DEFAULT;
|
|
26
|
+
this.readonlyStateNames = [];
|
|
27
|
+
this.on('ready', this.onReady.bind(this));
|
|
28
|
+
this.on('objectChange', this.onObjectChange.bind(this));
|
|
29
|
+
this.on('stateChange', this.onStateChange.bind(this));
|
|
28
30
|
// this.on('message', this.onMessage.bind(this));
|
|
29
|
-
this.on(
|
|
31
|
+
this.on('unload', this.onUnload.bind(this));
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
34
|
* Is called when databases are connected and adapter received configuration.
|
|
33
35
|
*/
|
|
34
36
|
onReady() {
|
|
35
|
-
var _a;
|
|
37
|
+
var _a, _b, _c, _d;
|
|
36
38
|
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
|
|
38
|
-
this.
|
|
39
|
-
this.
|
|
40
|
-
|
|
41
|
-
this.log.
|
|
42
|
-
yield comfortCloudClient.login(this.config.username, this.config.password);
|
|
43
|
-
this.log.info("Login successful.");
|
|
44
|
-
this.log.debug("Create devices.");
|
|
45
|
-
const groups = yield comfortCloudClient.getGroups();
|
|
46
|
-
this.createDevices(groups);
|
|
39
|
+
this.refreshIntervalInMinutes = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.refreshInterval) !== null && _b !== void 0 ? _b : REFRESH_INTERVAL_IN_MINUTES_DEFAULT;
|
|
40
|
+
this.subscribeStates('*');
|
|
41
|
+
this.setState('info.connection', false, true);
|
|
42
|
+
if (!((_c = this.config) === null || _c === void 0 ? void 0 : _c.username) || !((_d = this.config) === null || _d === void 0 ? void 0 : _d.password)) {
|
|
43
|
+
this.log.error('Can not start without username or password. Please open config.');
|
|
47
44
|
}
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
else {
|
|
46
|
+
try {
|
|
47
|
+
this.log.debug(`Try to login with username ${this.config.username}.`);
|
|
48
|
+
yield comfortCloudClient.login(this.config.username, this.config.password);
|
|
49
|
+
this.log.info('Login successful.');
|
|
50
|
+
this.setState('info.connection', true, true);
|
|
51
|
+
this.log.debug('Create devices.');
|
|
52
|
+
const groups = yield comfortCloudClient.getGroups();
|
|
53
|
+
yield this.createDevices(groups);
|
|
54
|
+
this.setupRefreshTimeout();
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
yield this.handleClientError(error);
|
|
58
|
+
}
|
|
50
59
|
}
|
|
51
60
|
});
|
|
52
61
|
}
|
|
53
62
|
refreshDeviceStates(device) {
|
|
54
|
-
this
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
63
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
+
this.log.debug(`Refresh device ${device.name} (${device.guid}).`);
|
|
65
|
+
this.log.debug(`${device.name}: guid => ${device.guid}.`);
|
|
66
|
+
this.log.debug(`${device.name}: operate => ${device.operate}.`);
|
|
67
|
+
yield this.setStateChangedAsync(`${device.name}.operate`, device.operate, true);
|
|
68
|
+
this.log.debug(`${device.name}: temperatureSet => ${device.temperatureSet}.`);
|
|
69
|
+
yield this.setStateChangedAsync(`${device.name}.temperatureSet`, device.temperatureSet, true);
|
|
70
|
+
this.log.debug(`${device.name}: insideTemperature => ${device.insideTemperature}.`);
|
|
71
|
+
yield this.setStateChangedAsync(`${device.name}.insideTemperature`, device.insideTemperature, true);
|
|
72
|
+
this.log.debug(`${device.name}: outTemperature => ${device.outTemperature}.`);
|
|
73
|
+
yield this.setStateChangedAsync(`${device.name}.outTemperature`, device.outTemperature, true);
|
|
74
|
+
this.log.debug(`${device.name}: airSwingLR => ${device.airSwingLR}.`);
|
|
75
|
+
yield this.setStateChangedAsync(`${device.name}.airSwingLR`, device.airSwingLR, true);
|
|
76
|
+
this.log.debug(`${device.name}: airSwingUD => ${device.airSwingUD}.`);
|
|
77
|
+
yield this.setStateChangedAsync(`${device.name}.airSwingUD`, device.airSwingUD, true);
|
|
78
|
+
this.log.debug(`${device.name}: fanAutoMode => ${device.fanAutoMode}.`);
|
|
79
|
+
yield this.setStateChangedAsync(`${device.name}.fanAutoMode`, device.fanAutoMode, true);
|
|
80
|
+
this.log.debug(`${device.name}: ecoMode => ${device.ecoMode}.`);
|
|
81
|
+
yield this.setStateChangedAsync(`${device.name}.ecoMode`, device.ecoMode, true);
|
|
82
|
+
this.log.debug(`${device.name}: operationMode => ${device.operationMode}.`);
|
|
83
|
+
yield this.setStateChangedAsync(`${device.name}.operationMode`, device.operationMode, true);
|
|
84
|
+
this.log.debug(`${device.name}: fanSpeed => ${device.fanSpeed}.`);
|
|
85
|
+
yield this.setStateChangedAsync(`${device.name}.fanSpeed`, device.fanSpeed, true);
|
|
86
|
+
this.log.debug(`${device.name}: actualNanoe => ${device.actualNanoe}.`);
|
|
87
|
+
yield this.setStateChangedAsync(`${device.name}.actualNanoe`, device.actualNanoe, true);
|
|
88
|
+
this.log.debug(`Refresh device ${device.name} finished.`);
|
|
89
|
+
});
|
|
80
90
|
}
|
|
81
91
|
refreshDevice(guid, deviceName) {
|
|
82
92
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -88,18 +98,19 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
88
98
|
if (!device.name) {
|
|
89
99
|
device.name = deviceName;
|
|
90
100
|
}
|
|
91
|
-
this.refreshDeviceStates(device);
|
|
101
|
+
yield this.refreshDeviceStates(device);
|
|
92
102
|
}
|
|
93
103
|
catch (error) {
|
|
94
|
-
this.handleClientError(error);
|
|
104
|
+
yield this.handleClientError(error);
|
|
95
105
|
}
|
|
96
106
|
});
|
|
97
107
|
}
|
|
98
108
|
refreshDevices() {
|
|
99
109
|
return __awaiter(this, void 0, void 0, function* () {
|
|
100
110
|
try {
|
|
101
|
-
this.log.debug(
|
|
111
|
+
this.log.debug('Refresh all devices.');
|
|
102
112
|
const groups = yield comfortCloudClient.getGroups();
|
|
113
|
+
this.setState('info.connection', true, true);
|
|
103
114
|
const devices = _.flatMap(groups, g => g.devices);
|
|
104
115
|
const deviceInfos = _.map(devices, d => { return { guid: d.guid, name: d.name }; });
|
|
105
116
|
yield Promise.all(deviceInfos.map((deviceInfo) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -107,12 +118,12 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
107
118
|
if (device != null) {
|
|
108
119
|
device.name = deviceInfo.name;
|
|
109
120
|
device.guid = deviceInfo.guid;
|
|
110
|
-
this.refreshDeviceStates(device);
|
|
121
|
+
yield this.refreshDeviceStates(device);
|
|
111
122
|
}
|
|
112
123
|
})));
|
|
113
124
|
}
|
|
114
125
|
catch (error) {
|
|
115
|
-
this.handleClientError(error);
|
|
126
|
+
yield this.handleClientError(error);
|
|
116
127
|
}
|
|
117
128
|
});
|
|
118
129
|
}
|
|
@@ -126,40 +137,49 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
126
137
|
const deviceInfos = _.map(devicesFromService, d => { return { guid: d.guid, name: d.name }; });
|
|
127
138
|
yield Promise.all(deviceInfos.map((deviceInfo) => __awaiter(this, void 0, void 0, function* () {
|
|
128
139
|
this.log.debug(`Device info from group ${deviceInfo.guid}, ${deviceInfo.name}.`);
|
|
129
|
-
|
|
140
|
+
let device = null;
|
|
141
|
+
try {
|
|
142
|
+
device = yield comfortCloudClient.getDevice(deviceInfo.guid);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
yield this.handleClientError(error);
|
|
146
|
+
}
|
|
130
147
|
if (device != null) {
|
|
131
148
|
if (_.includes(names, deviceInfo.name)) {
|
|
132
149
|
return;
|
|
133
150
|
}
|
|
134
151
|
this.createDevice(deviceInfo.name);
|
|
135
|
-
this.createState(deviceInfo.name,
|
|
136
|
-
this.
|
|
137
|
-
|
|
152
|
+
this.createState(deviceInfo.name, '', 'guid', { role: 'info.address', write: false, def: deviceInfo.guid, type: 'string' }, undefined);
|
|
153
|
+
this.readonlyStateNames.push('guid');
|
|
154
|
+
this.createState(deviceInfo.name, '', 'operate', {
|
|
155
|
+
role: 'switch.power',
|
|
138
156
|
states: { 0: panasonic_comfort_cloud_client_1.Power[0], 1: panasonic_comfort_cloud_client_1.Power[1] },
|
|
139
157
|
write: true,
|
|
140
158
|
def: device.operate,
|
|
141
|
-
type:
|
|
159
|
+
type: 'string',
|
|
142
160
|
}, undefined);
|
|
143
|
-
this.createState(deviceInfo.name,
|
|
144
|
-
role:
|
|
161
|
+
this.createState(deviceInfo.name, '', 'temperatureSet', {
|
|
162
|
+
role: 'level.temperature',
|
|
145
163
|
write: true,
|
|
146
164
|
def: device.temperatureSet,
|
|
147
|
-
type:
|
|
165
|
+
type: 'number',
|
|
148
166
|
}, undefined);
|
|
149
|
-
this.createState(deviceInfo.name,
|
|
150
|
-
role:
|
|
167
|
+
this.createState(deviceInfo.name, '', 'insideTemperature', {
|
|
168
|
+
role: 'level.temperature',
|
|
151
169
|
write: false,
|
|
152
170
|
def: device.insideTemperature,
|
|
153
|
-
type:
|
|
171
|
+
type: 'number',
|
|
154
172
|
}, undefined);
|
|
155
|
-
this.
|
|
156
|
-
|
|
173
|
+
this.readonlyStateNames.push('insideTemperature');
|
|
174
|
+
this.createState(deviceInfo.name, '', 'outTemperature', {
|
|
175
|
+
role: 'level.temperature',
|
|
157
176
|
write: false,
|
|
158
177
|
def: device.outTemperature,
|
|
159
|
-
type:
|
|
178
|
+
type: 'number',
|
|
160
179
|
}, undefined);
|
|
161
|
-
this.
|
|
162
|
-
|
|
180
|
+
this.readonlyStateNames.push('outTemperature');
|
|
181
|
+
this.createState(deviceInfo.name, '', 'airSwingLR', {
|
|
182
|
+
role: 'state',
|
|
163
183
|
states: {
|
|
164
184
|
0: panasonic_comfort_cloud_client_1.AirSwingLR[0],
|
|
165
185
|
1: panasonic_comfort_cloud_client_1.AirSwingLR[1],
|
|
@@ -169,10 +189,10 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
169
189
|
},
|
|
170
190
|
write: true,
|
|
171
191
|
def: device.airSwingLR,
|
|
172
|
-
type:
|
|
192
|
+
type: 'string',
|
|
173
193
|
}, undefined);
|
|
174
|
-
this.createState(deviceInfo.name,
|
|
175
|
-
role:
|
|
194
|
+
this.createState(deviceInfo.name, '', 'airSwingUD', {
|
|
195
|
+
role: 'state',
|
|
176
196
|
states: {
|
|
177
197
|
0: panasonic_comfort_cloud_client_1.AirSwingUD[0],
|
|
178
198
|
1: panasonic_comfort_cloud_client_1.AirSwingUD[1],
|
|
@@ -182,10 +202,10 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
182
202
|
},
|
|
183
203
|
write: true,
|
|
184
204
|
def: device.airSwingUD,
|
|
185
|
-
type:
|
|
205
|
+
type: 'string',
|
|
186
206
|
}, undefined);
|
|
187
|
-
this.createState(deviceInfo.name,
|
|
188
|
-
role:
|
|
207
|
+
this.createState(deviceInfo.name, '', 'fanAutoMode', {
|
|
208
|
+
role: 'state',
|
|
189
209
|
states: {
|
|
190
210
|
0: panasonic_comfort_cloud_client_1.FanAutoMode[0],
|
|
191
211
|
1: panasonic_comfort_cloud_client_1.FanAutoMode[1],
|
|
@@ -194,17 +214,17 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
194
214
|
},
|
|
195
215
|
write: true,
|
|
196
216
|
def: device.fanAutoMode,
|
|
197
|
-
type:
|
|
217
|
+
type: 'string',
|
|
198
218
|
}, undefined);
|
|
199
|
-
this.createState(deviceInfo.name,
|
|
200
|
-
role:
|
|
219
|
+
this.createState(deviceInfo.name, '', 'ecoMode', {
|
|
220
|
+
role: 'state',
|
|
201
221
|
states: { 0: panasonic_comfort_cloud_client_1.EcoMode[0], 1: panasonic_comfort_cloud_client_1.EcoMode[1], 2: panasonic_comfort_cloud_client_1.EcoMode[2] },
|
|
202
222
|
write: true,
|
|
203
223
|
def: device.ecoMode,
|
|
204
|
-
type:
|
|
224
|
+
type: 'string',
|
|
205
225
|
}, undefined);
|
|
206
|
-
this.createState(deviceInfo.name,
|
|
207
|
-
role:
|
|
226
|
+
this.createState(deviceInfo.name, '', 'operationMode', {
|
|
227
|
+
role: 'state',
|
|
208
228
|
states: {
|
|
209
229
|
0: panasonic_comfort_cloud_client_1.OperationMode[0],
|
|
210
230
|
1: panasonic_comfort_cloud_client_1.OperationMode[1],
|
|
@@ -214,10 +234,10 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
214
234
|
},
|
|
215
235
|
write: true,
|
|
216
236
|
def: device.operationMode,
|
|
217
|
-
type:
|
|
237
|
+
type: 'string',
|
|
218
238
|
}, undefined);
|
|
219
|
-
this.createState(deviceInfo.name,
|
|
220
|
-
role:
|
|
239
|
+
this.createState(deviceInfo.name, '', 'fanSpeed', {
|
|
240
|
+
role: 'state',
|
|
221
241
|
states: {
|
|
222
242
|
0: panasonic_comfort_cloud_client_1.FanSpeed[0],
|
|
223
243
|
1: panasonic_comfort_cloud_client_1.FanSpeed[1],
|
|
@@ -228,10 +248,10 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
228
248
|
},
|
|
229
249
|
write: true,
|
|
230
250
|
def: device.fanSpeed,
|
|
231
|
-
type:
|
|
251
|
+
type: 'string',
|
|
232
252
|
}, undefined);
|
|
233
|
-
this.createState(deviceInfo.name,
|
|
234
|
-
role:
|
|
253
|
+
this.createState(deviceInfo.name, '', 'actualNanoe', {
|
|
254
|
+
role: 'state',
|
|
235
255
|
states: {
|
|
236
256
|
0: panasonic_comfort_cloud_client_1.NanoeMode[0],
|
|
237
257
|
1: panasonic_comfort_cloud_client_1.NanoeMode[1],
|
|
@@ -241,17 +261,17 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
241
261
|
},
|
|
242
262
|
write: true,
|
|
243
263
|
def: device.actualNanoe,
|
|
244
|
-
type:
|
|
264
|
+
type: 'string',
|
|
245
265
|
}, undefined);
|
|
246
266
|
this.log.info(`Device ${deviceInfo.name} created.`);
|
|
247
267
|
}
|
|
248
268
|
})));
|
|
249
|
-
this.log.debug(
|
|
269
|
+
this.log.debug('Device creation completed.');
|
|
250
270
|
});
|
|
251
271
|
}
|
|
252
272
|
updateDevice(deviceName, stateName, state) {
|
|
253
273
|
return __awaiter(this, void 0, void 0, function* () {
|
|
254
|
-
if (stateName
|
|
274
|
+
if (this.readonlyStateNames.includes(stateName)) {
|
|
255
275
|
return;
|
|
256
276
|
}
|
|
257
277
|
if (!state.ack) {
|
|
@@ -274,7 +294,7 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
274
294
|
yield this.refreshDevice(guidState === null || guidState === void 0 ? void 0 : guidState.val, deviceName);
|
|
275
295
|
}
|
|
276
296
|
catch (error) {
|
|
277
|
-
this.handleClientError(error);
|
|
297
|
+
yield this.handleClientError(error);
|
|
278
298
|
}
|
|
279
299
|
}
|
|
280
300
|
});
|
|
@@ -283,10 +303,10 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
283
303
|
* Is called when adapter shuts down - callback has to be called under any circumstances!
|
|
284
304
|
*/
|
|
285
305
|
onUnload(callback) {
|
|
286
|
-
var _a;
|
|
287
306
|
try {
|
|
288
|
-
this.
|
|
289
|
-
|
|
307
|
+
if (this.refreshTimeout)
|
|
308
|
+
clearTimeout(this.refreshTimeout);
|
|
309
|
+
this.log.info('cleaned everything up...');
|
|
290
310
|
callback();
|
|
291
311
|
}
|
|
292
312
|
catch (e) {
|
|
@@ -310,35 +330,63 @@ class PanasonicComfortCloud extends utils.Adapter {
|
|
|
310
330
|
* Is called if a subscribed state changes
|
|
311
331
|
*/
|
|
312
332
|
onStateChange(id, state) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
333
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
334
|
+
if (state) {
|
|
335
|
+
const elements = id.split('.');
|
|
336
|
+
const deviceName = elements[elements.length - 2];
|
|
337
|
+
const stateName = elements[elements.length - 1];
|
|
338
|
+
try {
|
|
339
|
+
yield this.updateDevice(deviceName, stateName, state);
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
yield this.handleClientError(error);
|
|
343
|
+
}
|
|
344
|
+
// The state was changed
|
|
345
|
+
this.log.info(`state ${id} changed: ${state.val} (ack = ${state.ack})`);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
// The state was deleted
|
|
349
|
+
this.log.info(`state ${id} deleted`);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
325
352
|
}
|
|
326
353
|
handleClientError(error) {
|
|
327
354
|
return __awaiter(this, void 0, void 0, function* () {
|
|
328
|
-
this.log.debug(
|
|
355
|
+
this.log.debug('Try to handle error.');
|
|
329
356
|
if (error instanceof panasonic_comfort_cloud_client_1.TokenExpiredError) {
|
|
330
357
|
this.log.info(`Token of comfort cloud client expired. Trying to login again. Code=${error.code}. Stack: ${error.stack}`);
|
|
358
|
+
this.setState('info.connection', false, true);
|
|
331
359
|
yield comfortCloudClient.login(this.config.username, this.config.password);
|
|
332
|
-
this.
|
|
360
|
+
this.setState('info.connection', true, true);
|
|
361
|
+
this.log.info('Login successful.');
|
|
333
362
|
}
|
|
334
363
|
else if (error instanceof panasonic_comfort_cloud_client_1.ServiceError) {
|
|
364
|
+
this.setState('info.connection', false, true);
|
|
335
365
|
this.log.error(`Service error: ${error.message}. Code=${error.code}. Stack: ${error.stack}`);
|
|
336
366
|
}
|
|
337
|
-
else {
|
|
367
|
+
else if (error instanceof Error) {
|
|
338
368
|
this.log.error(`Unknown error: ${error}. Stack: ${error.stack}`);
|
|
339
369
|
}
|
|
340
370
|
});
|
|
341
371
|
}
|
|
372
|
+
setupRefreshTimeout() {
|
|
373
|
+
this.log.debug('setupRefreshTimeout');
|
|
374
|
+
const refreshIntervalInMilliseconds = this.refreshIntervalInMinutes * 60 * 1000;
|
|
375
|
+
this.log.debug(`refreshIntervalInMilliseconds=${refreshIntervalInMilliseconds}`);
|
|
376
|
+
this.refreshTimeout = setTimeout(this.refreshTimeoutFunc.bind(this), refreshIntervalInMilliseconds);
|
|
377
|
+
}
|
|
378
|
+
refreshTimeoutFunc() {
|
|
379
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
380
|
+
this.log.debug(`refreshTimeoutFunc started.`);
|
|
381
|
+
try {
|
|
382
|
+
yield this.refreshDevices();
|
|
383
|
+
this.setupRefreshTimeout();
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
yield this.handleClientError(error);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
342
390
|
}
|
|
343
391
|
if (module.parent) {
|
|
344
392
|
// Export the constructor in compact mode
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "panasonic-comfort-cloud",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.0.1",
|
|
5
5
|
"news": {
|
|
6
|
+
"2.0.1": {
|
|
7
|
+
"en": "Changed the type of some states from string to number.",
|
|
8
|
+
"de": "Den Typ von einigen States von string zu number geändert."
|
|
9
|
+
},
|
|
10
|
+
"2.0.0": {
|
|
11
|
+
"en": "Added js-controller 3 dependency.\nAdded username and password to protectedNative and password to encryptedNative.\nAdded connection info.\nChanged schdule to timeout for refresh.\nFixes for async await pattern.",
|
|
12
|
+
"de": "js-controller 3 als Abhängigkeit eingefügt.\nusername und password zu protectedNative und password zu encryptedNative hinzugefügt.\nconnection info als Status eingefügt.\nSchudle durch timeout für die Geräteaktualisierung erstezt.\nAsync und await überall korrekt berücksichtig."
|
|
13
|
+
},
|
|
14
|
+
"1.2.9": {
|
|
15
|
+
"en": "Error handling for get device added.",
|
|
16
|
+
"de": "Fehlerbehandlung beim Abrufen des Geräts hinzugefügt."
|
|
17
|
+
},
|
|
18
|
+
"1.2.8": {
|
|
19
|
+
"en": "Fixed bug in Comfort Cloud client.",
|
|
20
|
+
"de": "Fehler in Comfort Cloud client behoben."
|
|
21
|
+
},
|
|
22
|
+
"1.2.7": {
|
|
23
|
+
"en": "Comfort Cloud client updated.",
|
|
24
|
+
"de": "Comfort Cloud client aktualisiert."
|
|
25
|
+
},
|
|
6
26
|
"1.2.6": {
|
|
7
27
|
"en": "Fixed bug that guid is null in device creation.",
|
|
8
28
|
"de": "Fehler behoben, dass die GUID bei der Geräteerstellung null ist."
|
|
@@ -89,6 +109,8 @@
|
|
|
89
109
|
"keywords": ["air condition"],
|
|
90
110
|
"license": "MIT",
|
|
91
111
|
"platform": "Javascript/Node.js",
|
|
112
|
+
"connectionType": "cloud",
|
|
113
|
+
"dataSource": "poll",
|
|
92
114
|
"main": "build/main.js",
|
|
93
115
|
"icon": "panasonic-comfort-cloud.png",
|
|
94
116
|
"enabled": true,
|
|
@@ -99,17 +121,51 @@
|
|
|
99
121
|
"type": "climate-control",
|
|
100
122
|
"compact": true,
|
|
101
123
|
"materialize": true,
|
|
124
|
+
"globalDependencies": [
|
|
125
|
+
{
|
|
126
|
+
"admin": ">=4.0.9"
|
|
127
|
+
}
|
|
128
|
+
],
|
|
102
129
|
"dependencies": [
|
|
103
130
|
{
|
|
104
|
-
"js-controller": ">=
|
|
131
|
+
"js-controller": ">=3.0.0"
|
|
105
132
|
}
|
|
106
133
|
]
|
|
107
134
|
},
|
|
108
135
|
"native": {
|
|
109
136
|
"username": "",
|
|
110
|
-
"password": ""
|
|
137
|
+
"password": "",
|
|
138
|
+
"refreshInterval": 5
|
|
111
139
|
},
|
|
112
|
-
"protectedNative": [
|
|
140
|
+
"protectedNative": [
|
|
141
|
+
"username",
|
|
142
|
+
"password"
|
|
143
|
+
],
|
|
144
|
+
"encryptedNative": [
|
|
145
|
+
"password"
|
|
146
|
+
],
|
|
113
147
|
"objects": [],
|
|
114
|
-
"instanceObjects": [
|
|
148
|
+
"instanceObjects": [
|
|
149
|
+
{
|
|
150
|
+
"_id": "info",
|
|
151
|
+
"type": "channel",
|
|
152
|
+
"common": {
|
|
153
|
+
"name": "Information"
|
|
154
|
+
},
|
|
155
|
+
"native": {}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"_id": "info.connection",
|
|
159
|
+
"type": "state",
|
|
160
|
+
"common": {
|
|
161
|
+
"role": "indicator.connected",
|
|
162
|
+
"name": "Device or service connected",
|
|
163
|
+
"type": "boolean",
|
|
164
|
+
"read": true,
|
|
165
|
+
"write": false,
|
|
166
|
+
"def": false
|
|
167
|
+
},
|
|
168
|
+
"native": {}
|
|
169
|
+
}
|
|
170
|
+
]
|
|
115
171
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.panasonic-comfort-cloud",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Adapter for Panasonic Comfort Cloud",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "marc",
|
|
@@ -16,16 +16,14 @@
|
|
|
16
16
|
"url": "https://github.com/marc2016/ioBroker.panasonic-comfort-cloud"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@iobroker/adapter-core": "^2.
|
|
19
|
+
"@iobroker/adapter-core": "^2.5.1",
|
|
20
20
|
"@types/lodash": "^4.14.149",
|
|
21
|
-
"@types/node-schedule": "^1.3.0",
|
|
22
21
|
"lodash": "^4.17.15",
|
|
23
|
-
"
|
|
24
|
-
"panasonic-comfort-cloud-client": "^1.1.2",
|
|
22
|
+
"panasonic-comfort-cloud-client": "^1.1.4",
|
|
25
23
|
"ts-enum-util": "^4.0.1"
|
|
26
24
|
},
|
|
27
25
|
"devDependencies": {
|
|
28
|
-
"@iobroker/testing": "^
|
|
26
|
+
"@iobroker/testing": "^2.5.4",
|
|
29
27
|
"@types/chai": "^4.2.4",
|
|
30
28
|
"@types/chai-as-promised": "^7.1.2",
|
|
31
29
|
"@types/gulp": "^4.0.6",
|
|
@@ -48,7 +46,7 @@
|
|
|
48
46
|
"sinon-chai": "^3.3.0",
|
|
49
47
|
"source-map-support": "^0.5.16",
|
|
50
48
|
"ts-node": "^8.4.1",
|
|
51
|
-
"typescript": "^
|
|
49
|
+
"typescript": "^4.5.4"
|
|
52
50
|
},
|
|
53
51
|
"main": "build/main.js",
|
|
54
52
|
"scripts": {
|
|
@@ -60,7 +58,7 @@
|
|
|
60
58
|
"test:ts": "mocha --opts test/mocha.custom.opts",
|
|
61
59
|
"test:package": "mocha test/package --exit",
|
|
62
60
|
"test:unit": "mocha test/unit --exit",
|
|
63
|
-
"test:integration": "mocha test/integration --exit",
|
|
61
|
+
"test:integration": "mocha test/integration --timeout 120000 --exit",
|
|
64
62
|
"test": "npm run test:ts && npm run test:package",
|
|
65
63
|
"lint": "eslint --ext .ts src"
|
|
66
64
|
},
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Bug report
|
|
3
|
-
about: Something is not working as it should
|
|
4
|
-
title: ''
|
|
5
|
-
labels: ''
|
|
6
|
-
assignees: ''
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
**Describe the bug**
|
|
10
|
-
A clear and concise description of what the bug is.
|
|
11
|
-
|
|
12
|
-
**To Reproduce**
|
|
13
|
-
Steps to reproduce the behavior:
|
|
14
|
-
1. Go to '...'
|
|
15
|
-
2. Click on '...'
|
|
16
|
-
3. Scroll down to '....'
|
|
17
|
-
4. See error
|
|
18
|
-
|
|
19
|
-
**Expected behavior**
|
|
20
|
-
A clear and concise description of what you expected to happen.
|
|
21
|
-
|
|
22
|
-
**Screenshots & Logfiles**
|
|
23
|
-
If applicable, add screenshots and logfiles to help explain your problem.
|
|
24
|
-
|
|
25
|
-
**Versions:**
|
|
26
|
-
- Adapter version: <adapter-version>
|
|
27
|
-
- JS-Controller version: <js-controller-version> <!-- determine this with `iobroker -v` on the console -->
|
|
28
|
-
- Node version: <node-version> <!-- determine this with `node -v` on the console -->
|
|
29
|
-
- Operating system: <os-name>
|
|
30
|
-
|
|
31
|
-
**Additional context**
|
|
32
|
-
Add any other context about the problem here.
|
package/iob_npm.done
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|