homebridge-tasmota-control 0.0.26 → 0.3.34
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 +1 -75
- package/config.schema.json +49 -65
- package/index.js +123 -116
- package/package.json +44 -47
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-outlet
|
package/config.schema.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"pluginAlias": "
|
|
2
|
+
"pluginAlias": "tasmotaOutlet",
|
|
3
3
|
"pluginType": "platform",
|
|
4
4
|
"singular": true,
|
|
5
5
|
"headerDisplay": "This plugin works with Tasmota outlet 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
|
|
6
|
+
"footerDisplay": "This plugin is available [here](https://github.com/grzegorz914/homebridge-tasmota-outlet).",
|
|
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
|
+
"switchCount": {
|
|
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[].switchCount",
|
|
94
|
+
"devices[].enableDebugMode",
|
|
95
|
+
"devices[].disableLogInfo",
|
|
96
|
+
"devices[].refreshInterval"
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}]
|
|
117
101
|
}
|
package/index.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
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
|
-
const PLUGIN_NAME = 'homebridge-tasmota-
|
|
13
|
-
const PLATFORM_NAME = '
|
|
13
|
+
const PLUGIN_NAME = 'homebridge-tasmota-outlet';
|
|
14
|
+
const PLATFORM_NAME = 'tasmotaOutlet';
|
|
14
15
|
|
|
15
16
|
let Accessory, Characteristic, Service, Categories, UUID;
|
|
16
17
|
|
|
@@ -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,166 @@ 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.switchCount = config.switchCount || 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
|
-
this.relayState = false;
|
|
87
|
+
this.startPrepareAccessory = true;
|
|
87
88
|
this.prefDir = path.join(api.user.storagePath(), 'tasmota');
|
|
88
|
-
this.
|
|
89
|
-
this.url = 'http://' + this.host + '/cm?' + this.auth_url + '&cmnd='
|
|
89
|
+
this.url = `http://${this.host}/cm?user=${this.user}&password=${this.passwd}&cmnd=`
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
this.axiosInstance = axios.create({
|
|
92
|
+
method: 'GET',
|
|
93
|
+
baseURL: this.url,
|
|
94
|
+
timeout: 5000
|
|
95
|
+
});
|
|
95
96
|
|
|
96
97
|
//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
|
-
});
|
|
98
|
+
if (fs.existsSync(this.prefDir) == false) {
|
|
99
|
+
fsPromises.mkdir(this.prefDir);
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
//Check device state
|
|
108
103
|
setInterval(function () {
|
|
109
104
|
if (this.checkDeviceInfo) {
|
|
110
105
|
this.getDeviceInfo();
|
|
111
|
-
}
|
|
106
|
+
}
|
|
107
|
+
if (this.checkDeviceState) {
|
|
112
108
|
this.updateDeviceState();
|
|
113
109
|
}
|
|
114
110
|
}.bind(this), this.refreshInterval * 1000);
|
|
115
111
|
|
|
116
|
-
|
|
112
|
+
//start prepare accessory
|
|
117
113
|
}
|
|
118
114
|
|
|
119
115
|
async getDeviceInfo() {
|
|
120
|
-
|
|
116
|
+
this.log.debug('Device: %s %s, requesting Device Info.', this.host, this.name);
|
|
121
117
|
try {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
const response = await this.axiosInstance(STATUS);
|
|
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
|
+
this.log('-------- %s --------', deviceName);
|
|
124
|
+
this.log('Manufacturer: %s', this.manufacturer);
|
|
125
|
+
this.log('Hardware: %s', modelName);
|
|
126
|
+
this.log('Serialnr: %s', addressMac);
|
|
127
|
+
this.log('Firmware: %s', firmwareRevision);
|
|
128
|
+
this.log('----------------------------------');
|
|
129
|
+
|
|
130
|
+
this.modelName = modelName;
|
|
131
|
+
this.serialNumber = addressMac;
|
|
132
|
+
this.firmwareRevision = firmwareRevision;
|
|
133
|
+
|
|
134
|
+
this.checkDeviceInfo = false;
|
|
135
|
+
this.updateDeviceState();
|
|
132
136
|
} catch (error) {
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
this.log.error('Device: %s %s, Device Info eror: %s, state: Offline, trying to reconnect', this.host, this.name, error);
|
|
138
|
+
this.checkDeviceInfo = true;
|
|
135
139
|
}
|
|
136
140
|
}
|
|
137
141
|
|
|
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');
|
|
142
|
+
async updateDeviceState() {
|
|
143
|
+
this.log.debug('Device: %s %s, requesting Device state.', this.host, this.name);
|
|
144
|
+
try {
|
|
145
|
+
for (let i = 0; i < this.switchCount; i++) {
|
|
146
|
+
const channel = this.switchCount == 1 ? 'POWER' : 'POWER' + i;
|
|
147
|
+
const response = await this.axiosInstance(channel);
|
|
148
|
+
const debug = this.enableDebugMode ? this.log('Device: %s %s, debug response: %s', this.host, this.name, response.data) : false;
|
|
149
|
+
const powerState = (response.data[channel] != undefined) ? (response.data[channel] == 'ON') : false;
|
|
150
|
+
if (this.tasmotaServices) {
|
|
151
|
+
this.tasmotaServices[i]
|
|
152
|
+
.updateCharacteristic(Characteristic.OutletInUse, powerState);
|
|
153
153
|
}
|
|
154
|
-
me.relayState = powerState;
|
|
155
|
-
me.deviceDataOK = true;
|
|
156
154
|
}
|
|
155
|
+
this.checkDeviceState = true;
|
|
157
156
|
|
|
158
|
-
if (
|
|
159
|
-
|
|
157
|
+
if (this.startPrepareAccessory) {
|
|
158
|
+
this.prepareAccessory();
|
|
160
159
|
}
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
} catch (error) {
|
|
161
|
+
this.log.error('Device: %s %s, update Device state error: %s, state: Offline', this.host, this.name, error);
|
|
162
|
+
this.checkDeviceState = false;
|
|
163
|
+
this.checkDeviceInfo = true;
|
|
164
|
+
}
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
//Prepare accessory
|
|
166
168
|
prepareAccessory() {
|
|
167
169
|
this.log.debug('prepareAccessory');
|
|
168
170
|
const accessoryName = this.name;
|
|
169
|
-
const accessoryUUID = UUID.generate(
|
|
171
|
+
const accessoryUUID = UUID.generate(this.serialNumber);
|
|
170
172
|
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
|
-
}
|
|
173
|
+
const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
|
|
179
174
|
|
|
180
|
-
|
|
181
|
-
prepareInformationService() {
|
|
175
|
+
//Prepare information service
|
|
182
176
|
this.log.debug('prepareInformationService');
|
|
183
|
-
this.
|
|
177
|
+
const manufacturer = this.manufacturer;
|
|
178
|
+
const modelName = this.modelName;
|
|
179
|
+
const serialNumber = this.serialNumber;
|
|
180
|
+
const firmwareRevision = this.firmwareRevision;
|
|
184
181
|
|
|
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));
|
|
182
|
+
accessory.removeService(accessory.getService(Service.AccessoryInformation));
|
|
191
183
|
const informationService = new Service.AccessoryInformation();
|
|
192
184
|
informationService
|
|
193
|
-
.setCharacteristic(Characteristic.Name,
|
|
185
|
+
.setCharacteristic(Characteristic.Name, accessoryName)
|
|
194
186
|
.setCharacteristic(Characteristic.Manufacturer, manufacturer)
|
|
195
187
|
.setCharacteristic(Characteristic.Model, modelName)
|
|
196
188
|
.setCharacteristic(Characteristic.SerialNumber, serialNumber)
|
|
197
189
|
.setCharacteristic(Characteristic.FirmwareRevision, firmwareRevision);
|
|
198
190
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
this.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
191
|
+
accessory.addService(informationService);
|
|
192
|
+
|
|
193
|
+
//Prepare service
|
|
194
|
+
this.log.debug('prepareTasmotaService');
|
|
195
|
+
this.tasmotaServices = new Array();
|
|
196
|
+
for (let i = 0; i < this.switchCount; i++) {
|
|
197
|
+
const tasmotaService = new Service.Outlet(accessoryName, `tasmotaService${[i]}`);
|
|
198
|
+
tasmotaService.getCharacteristic(Characteristic.On)
|
|
199
|
+
.onGet(async () => {
|
|
200
|
+
const channel = this.switchCount == 1 ? 'POWER' : 'POWER' + i;
|
|
201
|
+
const response = await this.axiosInstance(channel);
|
|
202
|
+
const state = (response.data[channel] != undefined) ? (response.data[channel] == 'ON') : false;
|
|
203
|
+
const logInfo = this.disableLogInfo ? false : this.log('Device: %s, get state: %s', accessoryName, state ? 'ON' : 'OFF');
|
|
204
|
+
return state;
|
|
212
205
|
})
|
|
213
|
-
.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
206
|
+
.onSet(async (state) => {
|
|
207
|
+
const powerOn = this.switchCount == 1 ? POWER + ON : POWER + (i + 1) + ON;
|
|
208
|
+
const powerOff = this.switchCount == 1 ? POWER + OFF : POWER + (i + 1) + OFF;
|
|
209
|
+
state = state ? powerOn : powerOff;
|
|
210
|
+
this.axiosInstance(state);
|
|
211
|
+
const logInfo = this.disableLogInfo ? false : this.log('Device: %s, set state: %s', accessoryName, state ? 'ON' : 'OFF');
|
|
218
212
|
});
|
|
219
|
-
|
|
213
|
+
tasmotaService.getCharacteristic(Characteristic.OutletInUse)
|
|
214
|
+
.onGet(async () => {
|
|
215
|
+
const channel = this.switchCount == 1 ? 'POWER' : 'POWER' + i;
|
|
216
|
+
const response = await this.axiosInstance(channel);
|
|
217
|
+
const state = (response.data[channel] != undefined) ? (response.data[channel] == 'ON') : false;
|
|
218
|
+
const logInfo = this.disableLogInfo ? false : this.log('Device: %s, in use: %s', accessoryName, state ? 'YES' : 'NO');
|
|
219
|
+
return state;
|
|
220
|
+
});
|
|
221
|
+
this.tasmotaServices.push(tasmotaService);
|
|
222
|
+
accessory.addService(this.tasmotaServices[i]);
|
|
220
223
|
}
|
|
224
|
+
|
|
225
|
+
this.startPrepareAccessory = false;
|
|
226
|
+
this.log.debug('Device: %s %s, publishExternalAccessories.', this.host, accessoryName);
|
|
227
|
+
this.api.publishExternalAccessories(PLUGIN_NAME, [accessory]);
|
|
221
228
|
}
|
|
222
229
|
}
|
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.34",
|
|
5
|
+
"description": "Homebridge plugin (https://github.com/homebridge/homebridge) to control Tasmota outlet.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "grzegorz914",
|
|
8
|
+
"homepage": "https://github.com/grzegorz914/homebridge-tasmota-outlet#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/grzegorz914/homebridge-tasmota-outlet.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/grzegorz914/homebridge-tasmota-outlet/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
|
}
|