homebridge-tasmota-control 0.0.29 → 0.3.36
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/CHANGELOG.md +1 -1
- package/LICENSE +1 -1
- package/README.md +1 -75
- package/config.schema.json +50 -66
- package/index.js +123 -117
- package/package.json +44 -47
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,6 @@ All notable changes to this project will be documented in this file.
|
|
|
3
3
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
-
## [0.0.1] - (
|
|
6
|
+
## [0.0.1] - (24.12.2021)
|
|
7
7
|
## Changs
|
|
8
8
|
- initial release
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,75 +1 @@
|
|
|
1
|
-
|
|
2
|
-
<a href="https://github.com/grzegorz914/homebridge-tasmota-control"><img src="https://raw.githubusercontent.com/grzegorz914/homebridge-tasmota-control/master/graphics/tasmota.png" height="140"></a>
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
<span align="center">
|
|
6
|
-
|
|
7
|
-
# Homebridge tasmota
|
|
8
|
-
[](https://github.com/homebridge/homebridge/wiki/Verified-Plugins)
|
|
9
|
-
[](https://www.npmjs.com/package/homebridge-tasmota-control) [](https://www.npmjs.com/package/homebridge-tasmota-control)
|
|
10
|
-
[](https://github.com/grzegorz914/homebridge-tasmota-control/pulls)
|
|
11
|
-
[](https://github.com/grzegorz914/homebridge-tasmota-control/issues)
|
|
12
|
-
|
|
13
|
-
Homebridge plugin to control tasmota devices using RESTFull API.
|
|
14
|
-
|
|
15
|
-
</span>
|
|
16
|
-
|
|
17
|
-
## Package
|
|
18
|
-
1. [Homebridge](https://github.com/homebridge/homebridge)
|
|
19
|
-
2. [Homebridge Config UI X](https://github.com/oznu/homebridge-config-ui-x)
|
|
20
|
-
|
|
21
|
-
## Installation
|
|
22
|
-
1. Follow the step-by-step instructions on the [Homebridge Wiki](https://github.com/homebridge/homebridge/wiki) for how to install Homebridge.
|
|
23
|
-
2. Follow the step-by-step instructions on the [Homebridge Config UI X](https://github.com/oznu/homebridge-config-ui-x/wiki) for how to install Homebridge Config UI X.
|
|
24
|
-
3. Install homebridge-tasmota-control using: `npm install -g homebridge-tasmota-control` or search for `tasmota` in Config UI X.
|
|
25
|
-
|
|
26
|
-
## Know issues
|
|
27
|
-
1. If use with Hoobs possible config incompatibilty.
|
|
28
|
-
|
|
29
|
-
## HomeKit pairing
|
|
30
|
-
1. Each accessories needs to be manually paired.
|
|
31
|
-
2. Open the Home <img src='https://user-images.githubusercontent.com/3979615/78010622-4ea1d380-738e-11ea-8a17-e6a465eeec35.png' height='16.42px'> app on your device.
|
|
32
|
-
3. Tap the Home tab, then tap <img src='https://user-images.githubusercontent.com/3979615/78010869-9aed1380-738e-11ea-9644-9f46b3633026.png' height='16.42px'>.
|
|
33
|
-
4. Tap *Add Accessory*, and select *I Don't Have a Code or Cannot Scan*.
|
|
34
|
-
5. Enter the Homebridge PIN, this can be found under the QR code in Homebridge UI or your Homebridge logs, alternatively you can select *Use Camera* and scan the QR code again.
|
|
35
|
-
|
|
36
|
-
## Info
|
|
37
|
-
1. This plugin control ON/OFF Tasmota outlet.
|
|
38
|
-
2. More comming soon...
|
|
39
|
-
|
|
40
|
-
## Configuration
|
|
41
|
-
1. Use [Homebridge Config UI X](https://github.com/oznu/homebridge-config-ui-x) to configure the plugin (strongly recomended), or update your configuration file manually. See `sample-config.json` in this repository for a sample or add the bottom example to Your config.json file.
|
|
42
|
-
2. In `host` set the adres IP`
|
|
43
|
-
3. In `user` set the user.
|
|
44
|
-
4. In `passwd` set the password.
|
|
45
|
-
7. In `refreshInterval` set the data refresh time in seconds.
|
|
46
|
-
8. `manufacturer`, `model`, `serialNumber`, `firmwareRevision` - optional branding data displayed in Home.app
|
|
47
|
-
|
|
48
|
-
<p align="left">
|
|
49
|
-
<a href="https://github.com/grzegorz914/homebridge-tasmota-control"><img src="https://raw.githubusercontent.com/grzegorz914/homebridge-tasmota-control/master/graphics/ustawienia.png" height="150"></a>
|
|
50
|
-
</p>
|
|
51
|
-
|
|
52
|
-
```json
|
|
53
|
-
{
|
|
54
|
-
"platform": "TasmotaControl",
|
|
55
|
-
"devices": [
|
|
56
|
-
{
|
|
57
|
-
"name": "Gniazdo",
|
|
58
|
-
"host": "192.169.1.60",
|
|
59
|
-
"user": "user",
|
|
60
|
-
"paswd": "password",
|
|
61
|
-
"refreshInterval": 10,
|
|
62
|
-
"manufacturer": "Manufacturer",
|
|
63
|
-
"modelName": "Model",
|
|
64
|
-
"serialNumber": "Serial Number",
|
|
65
|
-
"firmwareRevision": "Firmware Revision"
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Whats new:
|
|
72
|
-
https://github.com/grzegorz914/homebridge-tasmota-control/blob/master/CHANGELOG.md
|
|
73
|
-
|
|
74
|
-
## Development
|
|
75
|
-
- Pull request and help in development highly appreciated.
|
|
1
|
+
# tasmota-control
|
package/config.schema.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"pluginAlias": "
|
|
2
|
+
"pluginAlias": "tasmotaControl",
|
|
3
3
|
"pluginType": "platform",
|
|
4
4
|
"singular": true,
|
|
5
|
-
"headerDisplay": "This plugin works with Tasmota
|
|
6
|
-
"footerDisplay": "This plugin
|
|
5
|
+
"headerDisplay": "This plugin works with Tasmota flashed devices and are exposed to HomeKit as separate accessories and each needs to be manually paired.\n\n1. Open the Home <img src='https://user-images.githubusercontent.com/3979615/78010622-4ea1d380-738e-11ea-8a17-e6a465eeec35.png' height='16.42px'> app on your device.\n2. Tap the Home tab, then tap <img src='https://user-images.githubusercontent.com/3979615/78010869-9aed1380-738e-11ea-9644-9f46b3633026.png' height='16.42px'>.\n3. Tap *Add Accessory*, and select *I Don't Have a Code or Cannot Scan*.\n4. Enter the Homebridge PIN, this can be found under the QR code in Homebridge UI or your Homebridge logs, alternatively you can select *Use Camera* and scan the QR code again.",
|
|
6
|
+
"footerDisplay": "This plugin is available [here](https://github.com/grzegorz914/homebridge-tasmota-control).",
|
|
7
7
|
"schema": {
|
|
8
8
|
"type": "object",
|
|
9
9
|
"properties": {
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
"host": {
|
|
23
23
|
"title": "IP Address",
|
|
24
24
|
"type": "string",
|
|
25
|
-
"default": "192.168.1.
|
|
25
|
+
"default": "192.168.1.61",
|
|
26
26
|
"required": true,
|
|
27
27
|
"format": "hostname"
|
|
28
28
|
},
|
|
29
29
|
"user": {
|
|
30
30
|
"title": "User",
|
|
31
31
|
"type": "string",
|
|
32
|
-
"default": "
|
|
32
|
+
"default": "admin",
|
|
33
33
|
"required": true
|
|
34
34
|
},
|
|
35
35
|
"passwd": {
|
|
@@ -42,76 +42,60 @@
|
|
|
42
42
|
"title": "Refresh interval (sec)",
|
|
43
43
|
"type": "integer",
|
|
44
44
|
"default": 10,
|
|
45
|
-
"
|
|
45
|
+
"minimum": 0,
|
|
46
|
+
"maximum": 60,
|
|
46
47
|
"required": true
|
|
47
48
|
},
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"type": "
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"name": "Model",
|
|
57
|
-
"type": "string",
|
|
58
|
-
"placeholder": "SP111",
|
|
59
|
-
"description": "Set the model name.",
|
|
60
|
-
"required": false
|
|
49
|
+
"channelsCount": {
|
|
50
|
+
"title": "Channels count",
|
|
51
|
+
"type": "number",
|
|
52
|
+
"default": 1,
|
|
53
|
+
"minimum": 1,
|
|
54
|
+
"maximum": 4,
|
|
55
|
+
"description": "Here set the number of channels.",
|
|
56
|
+
"required": true
|
|
61
57
|
},
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"type": "
|
|
65
|
-
"
|
|
66
|
-
"description": "
|
|
58
|
+
"enableDebugMode": {
|
|
59
|
+
"title": "Enable Debug Mode",
|
|
60
|
+
"type": "boolean",
|
|
61
|
+
"default": false,
|
|
62
|
+
"description": "This enable debug mode.",
|
|
67
63
|
"required": false
|
|
68
64
|
},
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"type": "
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
65
|
+
"disableLogInfo": {
|
|
66
|
+
"title": "Disable log info",
|
|
67
|
+
"type": "boolean",
|
|
68
|
+
"default": false,
|
|
69
|
+
"required": false,
|
|
70
|
+
"description": "This disable log info, all values and state will not be displayed in Homebridge log console."
|
|
75
71
|
}
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
74
|
}
|
|
79
75
|
}
|
|
80
76
|
},
|
|
81
|
-
"layout": [
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"devices[]
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
]
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
"expandable": true,
|
|
106
|
-
"expanded": false,
|
|
107
|
-
"items": [
|
|
108
|
-
"devices[].manufacturer",
|
|
109
|
-
"devices[].modelName",
|
|
110
|
-
"devices[].serialNumber",
|
|
111
|
-
"devices[].firmwareRevision"
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
}
|
|
116
|
-
]
|
|
77
|
+
"layout": [{
|
|
78
|
+
"key": "devices",
|
|
79
|
+
"type": "tabarray",
|
|
80
|
+
"title": "{{ value.name || 'new device' }}",
|
|
81
|
+
"items": [
|
|
82
|
+
"devices[].name",
|
|
83
|
+
"devices[].host",
|
|
84
|
+
{
|
|
85
|
+
"key": "devices[]",
|
|
86
|
+
"type": "section",
|
|
87
|
+
"title": "Advanced Settings",
|
|
88
|
+
"expandable": true,
|
|
89
|
+
"expanded": false,
|
|
90
|
+
"items": [
|
|
91
|
+
"devices[].user",
|
|
92
|
+
"devices[].passwd",
|
|
93
|
+
"devices[].channelsCount",
|
|
94
|
+
"devices[].enableDebugMode",
|
|
95
|
+
"devices[].disableLogInfo",
|
|
96
|
+
"devices[].refreshInterval"
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}]
|
|
117
101
|
}
|
package/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const request = require('request');
|
|
4
|
-
const axios = require('axios').default;
|
|
5
|
-
const fs = require('fs');
|
|
6
3
|
const path = require('path');
|
|
4
|
+
const axios = require('axios');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const fsPromises = require('fs').promises;
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
8
|
+
const STATUS = 'Status0';
|
|
9
|
+
const POWER = 'Power';
|
|
10
|
+
const ON = '%20on'
|
|
11
|
+
const OFF = '%20off';
|
|
11
12
|
|
|
12
13
|
const PLUGIN_NAME = 'homebridge-tasmota-control';
|
|
13
14
|
const PLATFORM_NAME = 'tasmotaControl';
|
|
@@ -31,31 +32,31 @@ class tasmotaPlatform {
|
|
|
31
32
|
return;
|
|
32
33
|
}
|
|
33
34
|
this.log = log;
|
|
34
|
-
this.config = config;
|
|
35
35
|
this.api = api;
|
|
36
36
|
this.devices = config.devices || [];
|
|
37
|
+
this.accessories = [];
|
|
37
38
|
|
|
38
39
|
this.api.on('didFinishLaunching', () => {
|
|
39
40
|
this.log.debug('didFinishLaunching');
|
|
40
41
|
for (let i = 0; i < this.devices.length; i++) {
|
|
41
|
-
|
|
42
|
-
if (!
|
|
42
|
+
const device = this.devices[i];
|
|
43
|
+
if (!device.name) {
|
|
43
44
|
this.log.warn('Device Name Missing');
|
|
44
45
|
} else {
|
|
45
|
-
new tasmotaDevice(this.log,
|
|
46
|
+
new tasmotaDevice(this.log, device, this.api);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
});
|
|
49
|
-
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
configureAccessory(
|
|
53
|
-
this.log.debug('
|
|
52
|
+
configureAccessory(accessory) {
|
|
53
|
+
this.log.debug('configureAccessory');
|
|
54
|
+
this.accessories.push(accessory);
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
removeAccessory(
|
|
57
|
-
this.log.debug('
|
|
58
|
-
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
|
|
57
|
+
removeAccessory(accessory) {
|
|
58
|
+
this.log.debug('removeAccessory');
|
|
59
|
+
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
@@ -63,160 +64,165 @@ class tasmotaDevice {
|
|
|
63
64
|
constructor(log, config, api) {
|
|
64
65
|
this.log = log;
|
|
65
66
|
this.api = api;
|
|
66
|
-
this.config = config;
|
|
67
|
-
|
|
68
67
|
|
|
69
68
|
//device configuration
|
|
70
69
|
this.name = config.name;
|
|
71
70
|
this.host = config.host;
|
|
72
71
|
this.user = config.user;
|
|
73
72
|
this.passwd = config.passwd;
|
|
74
|
-
this.refreshInterval = config.refreshInterval ||
|
|
73
|
+
this.refreshInterval = config.refreshInterval || 5;
|
|
74
|
+
this.channelsCount = config.channelsCount || 1;
|
|
75
|
+
this.enableDebugMode = config.enableDebugMode || false;
|
|
76
|
+
this.disableLogInfo = config.disableLogInfo || true;
|
|
75
77
|
|
|
76
78
|
//get Device info
|
|
77
|
-
this.manufacturer =
|
|
78
|
-
this.modelName =
|
|
79
|
-
this.serialNumber =
|
|
80
|
-
this.firmwareRevision =
|
|
79
|
+
this.manufacturer = 'Tasmota';
|
|
80
|
+
this.modelName = 'Model Name';
|
|
81
|
+
this.serialNumber = 'Serial Number';
|
|
82
|
+
this.firmwareRevision = 'Firmware Revision';
|
|
81
83
|
|
|
82
84
|
//setup variables
|
|
83
|
-
this.checkDeviceInfo =
|
|
85
|
+
this.checkDeviceInfo = true;
|
|
84
86
|
this.checkDeviceState = false;
|
|
85
|
-
this.
|
|
86
|
-
|
|
87
|
+
this.startPrepareAccessory = true;
|
|
88
|
+
|
|
87
89
|
this.prefDir = path.join(api.user.storagePath(), 'tasmota');
|
|
88
|
-
this.
|
|
89
|
-
this.url = 'http://' + this.host + '/cm?' + this.auth_url + '&cmnd='
|
|
90
|
+
this.url = `http://${this.host}/cm?user=${this.user}&password=${this.passwd}&cmnd=`
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
this.axiosInstance = axios.create({
|
|
93
|
+
method: 'GET',
|
|
94
|
+
baseURL: this.url,
|
|
95
|
+
timeout: 5000
|
|
96
|
+
});
|
|
95
97
|
|
|
96
98
|
//check if the directory exists, if not then create it
|
|
97
|
-
if (fs.existsSync(this.prefDir)
|
|
98
|
-
|
|
99
|
-
if (error) {
|
|
100
|
-
this.log.error('Device: %s , create directory: %s, error: %s', this.name, this.prefDir, error);
|
|
101
|
-
} else {
|
|
102
|
-
this.log.debug('Device: %s , create directory successful: %s', this.name, this.prefDir);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
99
|
+
if (fs.existsSync(this.prefDir) == false) {
|
|
100
|
+
fsPromises.mkdir(this.prefDir);
|
|
105
101
|
}
|
|
106
102
|
|
|
107
103
|
//Check device state
|
|
108
104
|
setInterval(function () {
|
|
109
105
|
if (this.checkDeviceInfo) {
|
|
110
106
|
this.getDeviceInfo();
|
|
111
|
-
} else
|
|
107
|
+
} else {
|
|
112
108
|
this.updateDeviceState();
|
|
113
109
|
}
|
|
114
110
|
}.bind(this), this.refreshInterval * 1000);
|
|
115
|
-
|
|
116
|
-
this.getDeviceInfo()
|
|
117
111
|
}
|
|
118
112
|
|
|
119
113
|
async getDeviceInfo() {
|
|
120
|
-
|
|
114
|
+
this.log.debug('Device: %s %s, requesting Device Info.', this.host, this.name);
|
|
121
115
|
try {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
116
|
+
const response = await this.axiosInstance(STATUS);
|
|
117
|
+
const debug = this.enableDebugMode ? this.log('Device: %s %s, debug response: %s', this.host, this.name, response.data) : false;
|
|
118
|
+
|
|
119
|
+
const deviceName = response.data.Status.DeviceName;
|
|
120
|
+
const modelName = response.data.StatusFWR.Hardware;
|
|
121
|
+
const addressMac = response.data.StatusNET.Mac;
|
|
122
|
+
const firmwareRevision = response.data.StatusFWR.Version;
|
|
123
|
+
|
|
124
|
+
this.log('-------- %s --------', deviceName);
|
|
125
|
+
this.log('Manufacturer: %s', this.manufacturer);
|
|
126
|
+
this.log('Hardware: %s', modelName);
|
|
127
|
+
this.log('Serialnr: %s', addressMac);
|
|
128
|
+
this.log('Firmware: %s', firmwareRevision);
|
|
129
|
+
this.log('----------------------------------');
|
|
130
|
+
|
|
131
|
+
this.modelName = modelName;
|
|
132
|
+
this.serialNumber = addressMac;
|
|
133
|
+
this.firmwareRevision = firmwareRevision;
|
|
134
|
+
|
|
135
|
+
this.checkDeviceInfo = false;
|
|
136
|
+
if (this.startPrepareAccessory) {
|
|
137
|
+
this.prepareAccessory();
|
|
138
|
+
}
|
|
132
139
|
} catch (error) {
|
|
133
|
-
|
|
134
|
-
|
|
140
|
+
this.log.error('Device: %s %s, Device Info eror: %s, state: Offline, trying to reconnect', this.host, this.name, error);
|
|
141
|
+
this.checkDeviceInfo = true;
|
|
135
142
|
}
|
|
136
143
|
}
|
|
137
144
|
|
|
138
|
-
updateDeviceState() {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
let powerState = data.power;
|
|
150
|
-
if (me.tasmotaService) {
|
|
151
|
-
me.tasmotaService.updateCharacteristic(Characteristic.On, powerState);
|
|
152
|
-
me.log.debug('Device: %s, state: %s', me.name, powerState ? 'ON' : 'OFF');
|
|
145
|
+
async updateDeviceState() {
|
|
146
|
+
this.log.debug('Device: %s %s, requesting Device state.', this.host, this.name);
|
|
147
|
+
try {
|
|
148
|
+
for (let i = 0; i < this.channelsCount; i++) {
|
|
149
|
+
const channel = this.channelsCount == 1 ? 'POWER' : 'POWER' + i;
|
|
150
|
+
const response = await this.axiosInstance(channel);
|
|
151
|
+
const debug = this.enableDebugMode ? this.log('Device: %s %s, debug response: %s', this.host, this.name, response.data) : false;
|
|
152
|
+
const powerState = (response.data[channel] != undefined) ? (response.data[channel] == 'ON') : false;
|
|
153
|
+
if (this.tasmotaServices) {
|
|
154
|
+
this.tasmotaServices[i]
|
|
155
|
+
.updateCharacteristic(Characteristic.OutletInUse, powerState);
|
|
153
156
|
}
|
|
154
|
-
me.relayState = powerState;
|
|
155
|
-
me.deviceDataOK = true;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!me.checkDeviceState) {
|
|
159
|
-
me.prepareAccessory();
|
|
160
157
|
}
|
|
161
|
-
|
|
162
|
-
})
|
|
158
|
+
this.checkDeviceState = true;
|
|
159
|
+
} catch (error) {
|
|
160
|
+
this.log.error('Device: %s %s, update Device state error: %s, state: Offline', this.host, this.name, error);
|
|
161
|
+
this.checkDeviceState = false;
|
|
162
|
+
this.checkDeviceInfo = true;
|
|
163
|
+
}
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
//Prepare accessory
|
|
166
167
|
prepareAccessory() {
|
|
167
168
|
this.log.debug('prepareAccessory');
|
|
168
169
|
const accessoryName = this.name;
|
|
169
|
-
const accessoryUUID = UUID.generate(
|
|
170
|
+
const accessoryUUID = UUID.generate(this.serialNumber);
|
|
170
171
|
const accessoryCategory = Categories.OTHER;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
this.prepareInformationService();
|
|
174
|
-
this.preparetasmotaService();
|
|
175
|
-
|
|
176
|
-
this.log.debug('Device: %s %s, publishExternalAccessories.', this.host, accessoryName);
|
|
177
|
-
this.api.publishExternalAccessories(PLUGIN_NAME, [this.accessory]);
|
|
178
|
-
}
|
|
172
|
+
const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
|
|
179
173
|
|
|
180
|
-
|
|
181
|
-
prepareInformationService() {
|
|
174
|
+
//Prepare information service
|
|
182
175
|
this.log.debug('prepareInformationService');
|
|
183
|
-
this.
|
|
176
|
+
const manufacturer = this.manufacturer;
|
|
177
|
+
const modelName = this.modelName;
|
|
178
|
+
const serialNumber = this.serialNumber;
|
|
179
|
+
const firmwareRevision = this.firmwareRevision;
|
|
184
180
|
|
|
185
|
-
|
|
186
|
-
let modelName = this.modelName;
|
|
187
|
-
let serialNumber = this.serialNumber;
|
|
188
|
-
let firmwareRevision = this.firmwareRevision;
|
|
189
|
-
|
|
190
|
-
this.accessory.removeService(this.accessory.getService(Service.AccessoryInformation));
|
|
181
|
+
accessory.removeService(accessory.getService(Service.AccessoryInformation));
|
|
191
182
|
const informationService = new Service.AccessoryInformation();
|
|
192
183
|
informationService
|
|
193
|
-
.setCharacteristic(Characteristic.Name,
|
|
184
|
+
.setCharacteristic(Characteristic.Name, accessoryName)
|
|
194
185
|
.setCharacteristic(Characteristic.Manufacturer, manufacturer)
|
|
195
186
|
.setCharacteristic(Characteristic.Model, modelName)
|
|
196
187
|
.setCharacteristic(Characteristic.SerialNumber, serialNumber)
|
|
197
188
|
.setCharacteristic(Characteristic.FirmwareRevision, firmwareRevision);
|
|
198
189
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
this.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
190
|
+
accessory.addService(informationService);
|
|
191
|
+
|
|
192
|
+
//Prepare service
|
|
193
|
+
this.log.debug('prepareTasmotaService');
|
|
194
|
+
this.tasmotaServices = new Array();
|
|
195
|
+
for (let i = 0; i < this.channelsCount; i++) {
|
|
196
|
+
const tasmotaService = new Service.Outlet(accessoryName, `tasmotaService${[i]}`);
|
|
197
|
+
tasmotaService.getCharacteristic(Characteristic.On)
|
|
198
|
+
.onGet(async () => {
|
|
199
|
+
const channel = this.channelsCount == 1 ? 'POWER' : 'POWER' + i;
|
|
200
|
+
const response = await this.axiosInstance(channel);
|
|
201
|
+
const state = (response.data[channel] != undefined) ? (response.data[channel] == 'ON') : false;
|
|
202
|
+
const logInfo = this.disableLogInfo ? false : this.log('Device: %s, get state: %s', accessoryName, state ? 'ON' : 'OFF');
|
|
203
|
+
return state;
|
|
212
204
|
})
|
|
213
|
-
.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
205
|
+
.onSet(async (state) => {
|
|
206
|
+
const powerOn = this.channelsCount == 1 ? POWER + ON : POWER + (i + 1) + ON;
|
|
207
|
+
const powerOff = this.channelsCount == 1 ? POWER + OFF : POWER + (i + 1) + OFF;
|
|
208
|
+
state = state ? powerOn : powerOff;
|
|
209
|
+
this.axiosInstance(state);
|
|
210
|
+
const logInfo = this.disableLogInfo ? false : this.log('Device: %s, set state: %s', accessoryName, state ? 'ON' : 'OFF');
|
|
218
211
|
});
|
|
219
|
-
|
|
212
|
+
tasmotaService.getCharacteristic(Characteristic.OutletInUse)
|
|
213
|
+
.onGet(async () => {
|
|
214
|
+
const channel = this.channelsCount == 1 ? 'POWER' : 'POWER' + i;
|
|
215
|
+
const response = await this.axiosInstance(channel);
|
|
216
|
+
const state = (response.data[channel] != undefined) ? (response.data[channel] == 'ON') : false;
|
|
217
|
+
const logInfo = this.disableLogInfo ? false : this.log('Device: %s, in use: %s', accessoryName, state ? 'YES' : 'NO');
|
|
218
|
+
return state;
|
|
219
|
+
});
|
|
220
|
+
this.tasmotaServices.push(tasmotaService);
|
|
221
|
+
accessory.addService(this.tasmotaServices[i]);
|
|
220
222
|
}
|
|
223
|
+
|
|
224
|
+
this.startPrepareAccessory = false;
|
|
225
|
+
this.log.debug('Device: %s %s, publishExternalAccessories.', this.host, accessoryName);
|
|
226
|
+
this.api.publishExternalAccessories(PLUGIN_NAME, [accessory]);
|
|
221
227
|
}
|
|
222
228
|
}
|
package/package.json
CHANGED
|
@@ -1,49 +1,46 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
"scripts": {
|
|
47
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
48
|
-
}
|
|
2
|
+
"displayName": "Tasmota Control",
|
|
3
|
+
"name": "homebridge-tasmota-control",
|
|
4
|
+
"version": "0.3.36",
|
|
5
|
+
"description": "Homebridge plugin (https://github.com/homebridge/homebridge) to control Tasmota flashed devices.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "grzegorz914",
|
|
8
|
+
"homepage": "https://github.com/grzegorz914/homebridge-tasmota-control#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/grzegorz914/homebridge-tasmota-control.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/grzegorz914/homebridge-tasmota-control/issues"
|
|
15
|
+
},
|
|
16
|
+
"funding": {
|
|
17
|
+
"type": "paypal",
|
|
18
|
+
"url": "https://paypal.me/GrzegorzKaczor"
|
|
19
|
+
},
|
|
20
|
+
"main": "index.js",
|
|
21
|
+
"files": [
|
|
22
|
+
"index.js",
|
|
23
|
+
"config.schema.json",
|
|
24
|
+
"package.json",
|
|
25
|
+
"CHANGELOG.md",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=12.0.0",
|
|
31
|
+
"homebridge": ">=1.3.0"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"axios": ">=0.24.0"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"homebridge",
|
|
38
|
+
"homebridge-plugin",
|
|
39
|
+
"homekit",
|
|
40
|
+
"tasmota"
|
|
41
|
+
],
|
|
42
|
+
"contributors": [],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
45
|
+
}
|
|
49
46
|
}
|