homebridge-tuya-community 3.3.0
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/.eslintrc.js +29 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/new-device.md +24 -0
- package/.github/workflows/codeql-analysis.yml +67 -0
- package/.github/workflows/eslint.yml +28 -0
- package/Changelog.md +87 -0
- package/LICENSE +21 -0
- package/Readme.MD +99 -0
- package/assets/Tuya-Plugin-Branding.png +0 -0
- package/bin/cli-decode.js +197 -0
- package/bin/cli-find.js +207 -0
- package/bin/cli.js +13 -0
- package/config-example.MD +43 -0
- package/config.schema.json +554 -0
- package/index.js +288 -0
- package/lib/AirConditionerAccessory.js +445 -0
- package/lib/AirPurifierAccessory.js +531 -0
- package/lib/BaseAccessory.js +292 -0
- package/lib/ConvectorAccessory.js +313 -0
- package/lib/CustomMultiLightAccessory.js +70 -0
- package/lib/CustomMultiOutletAccessory.js +111 -0
- package/lib/DehumidifierAccessory.js +301 -0
- package/lib/EnergyCharacteristics.js +86 -0
- package/lib/GarageDoorAccessory.js +307 -0
- package/lib/MultiLightAccessory.js +64 -0
- package/lib/MultiOutletAccessory.js +106 -0
- package/lib/OilDiffuserAccessory.js +480 -0
- package/lib/OutletAccessory.js +83 -0
- package/lib/RGBTWLightAccessory.js +234 -0
- package/lib/RGBTWOutletAccessory.js +296 -0
- package/lib/SimpleBlindsAccessory.js +298 -0
- package/lib/SimpleDimmer2Accessory.js +54 -0
- package/lib/SimpleDimmerAccessory.js +54 -0
- package/lib/SimpleFanAccessory.js +132 -0
- package/lib/SimpleFanLightAccessory.js +205 -0
- package/lib/SimpleHeaterAccessory.js +154 -0
- package/lib/SimpleLightAccessory.js +39 -0
- package/lib/SingleLightAccessory.js +45 -0
- package/lib/SwitchAccessory.js +106 -0
- package/lib/TWLightAccessory.js +91 -0
- package/lib/TuyaAccessory.js +744 -0
- package/lib/TuyaDiscovery.js +278 -0
- package/lib/ValveAccessory.js +150 -0
- package/package.json +49 -0
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
env: {
|
|
3
|
+
node: true,
|
|
4
|
+
es2021: true
|
|
5
|
+
},
|
|
6
|
+
extends: 'eslint:recommended',
|
|
7
|
+
parserOptions: {
|
|
8
|
+
ecmaVersion: 'latest',
|
|
9
|
+
sourceType: 'script'
|
|
10
|
+
},
|
|
11
|
+
rules: {
|
|
12
|
+
// Relaxed for legacy codebase - only critical errors
|
|
13
|
+
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
|
14
|
+
'no-console': 'off',
|
|
15
|
+
'no-empty': 'warn',
|
|
16
|
+
'no-constant-condition': 'warn',
|
|
17
|
+
'no-prototype-builtins': 'off',
|
|
18
|
+
'no-case-declarations': 'off',
|
|
19
|
+
|
|
20
|
+
// Disable style rules for legacy code
|
|
21
|
+
'semi': 'off',
|
|
22
|
+
'quotes': 'off',
|
|
23
|
+
'indent': 'off',
|
|
24
|
+
'comma-dangle': 'off',
|
|
25
|
+
'no-trailing-spaces': 'off',
|
|
26
|
+
'eol-last': 'off'
|
|
27
|
+
},
|
|
28
|
+
ignorePatterns: ['node_modules/', 'package-lock.json']
|
|
29
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: ''
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: iRayanKhan
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Checklist**
|
|
11
|
+
- [ ] I have read the common issues wiki page
|
|
12
|
+
- [ ] I have checked to make sure the plugin is up to date
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
**Describe the bug**
|
|
17
|
+
A clear and concise description of what the bug is.
|
|
18
|
+
|
|
19
|
+
**To Reproduce**
|
|
20
|
+
Steps to reproduce the behavior:
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
**Expected behavior**
|
|
24
|
+
A clear and concise description of what you expected to happen.
|
|
25
|
+
|
|
26
|
+
**Screenshots**
|
|
27
|
+
If applicable, add screenshots to help explain your problem.
|
|
28
|
+
|
|
29
|
+
**Environment (please complete the following information):**
|
|
30
|
+
- OS:
|
|
31
|
+
- iOS version:
|
|
32
|
+
- Homehubs:
|
|
33
|
+
- Node Version:
|
|
34
|
+
- Plugin Version:
|
|
35
|
+
- Accessory Type
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
**Additional context**
|
|
40
|
+
Add any other context about the problem here.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: New Device
|
|
3
|
+
about: Question regarding support for a new device.
|
|
4
|
+
title: 'New Device: '
|
|
5
|
+
labels: 'newDevice'
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Describe your device**
|
|
10
|
+
A clear and concise description of what your device is, such as accessory type, and product description.
|
|
11
|
+
|
|
12
|
+
Example: Generic Brand Lightbulb with Hex Color support, and 255 brightness.
|
|
13
|
+
|
|
14
|
+
**Partial Support?**
|
|
15
|
+
Does this device work in any fashion in the plugin?
|
|
16
|
+
|
|
17
|
+
**Device Schema**
|
|
18
|
+
Please print your devices schema below:
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
**Additional context**
|
|
22
|
+
Add any other context about the problem here.
|
|
23
|
+
|
|
24
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# For most projects, this workflow file will not need changing; you simply need
|
|
2
|
+
# to commit it to your repository.
|
|
3
|
+
#
|
|
4
|
+
# You may wish to alter this file to override the set of languages analyzed,
|
|
5
|
+
# or to provide custom queries or build logic.
|
|
6
|
+
#
|
|
7
|
+
# ******** NOTE ********
|
|
8
|
+
# We have attempted to detect the languages in your repository. Please check
|
|
9
|
+
# the `language` matrix defined below to confirm you have the correct set of
|
|
10
|
+
# supported CodeQL languages.
|
|
11
|
+
#
|
|
12
|
+
name: "CodeQL"
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [ master ]
|
|
17
|
+
pull_request:
|
|
18
|
+
# The branches below must be a subset of the branches above
|
|
19
|
+
branches: [ master ]
|
|
20
|
+
schedule:
|
|
21
|
+
- cron: '31 12 * * 5'
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
analyze:
|
|
25
|
+
name: Analyze
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
|
|
28
|
+
strategy:
|
|
29
|
+
fail-fast: false
|
|
30
|
+
matrix:
|
|
31
|
+
language: [ 'javascript' ]
|
|
32
|
+
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
|
33
|
+
# Learn more:
|
|
34
|
+
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
|
35
|
+
|
|
36
|
+
steps:
|
|
37
|
+
- name: Checkout repository
|
|
38
|
+
uses: actions/checkout@v2
|
|
39
|
+
|
|
40
|
+
# Initializes the CodeQL tools for scanning.
|
|
41
|
+
- name: Initialize CodeQL
|
|
42
|
+
uses: github/codeql-action/init@v1
|
|
43
|
+
with:
|
|
44
|
+
languages: ${{ matrix.language }}
|
|
45
|
+
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
46
|
+
# By default, queries listed here will override any specified in a config file.
|
|
47
|
+
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
48
|
+
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
49
|
+
|
|
50
|
+
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
51
|
+
# If this step fails, then you should remove it and run the build manually (see below)
|
|
52
|
+
- name: Autobuild
|
|
53
|
+
uses: github/codeql-action/autobuild@v1
|
|
54
|
+
|
|
55
|
+
# ℹ️ Command-line programs to run using the OS shell.
|
|
56
|
+
# 📚 https://git.io/JvXDl
|
|
57
|
+
|
|
58
|
+
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
59
|
+
# and modify them (or add more) to build your code if your project
|
|
60
|
+
# uses a compiled language
|
|
61
|
+
|
|
62
|
+
#- run: |
|
|
63
|
+
# make bootstrap
|
|
64
|
+
# make release
|
|
65
|
+
|
|
66
|
+
- name: Perform CodeQL Analysis
|
|
67
|
+
uses: github/codeql-action/analyze@v1
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: ESLint
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master, main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master, main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
eslint:
|
|
11
|
+
name: Run ESLint
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout code
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Setup Node.js
|
|
19
|
+
uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: '20'
|
|
22
|
+
cache: 'npm'
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: npm ci
|
|
26
|
+
|
|
27
|
+
- name: Run ESLint
|
|
28
|
+
run: npm run lint
|
package/Changelog.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. This project uses [semantic versioning](https://semver.org/).
|
|
4
|
+
|
|
5
|
+
## 3.3.0 (2026-01-09)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Light Switch support** - Multi-gang light switches with separate HomeKit accessories per gang
|
|
9
|
+
- `MultiLight` type for sequential DPs (1, 2, 3...)
|
|
10
|
+
- `CustomMultiLight` type for custom DP mappings with per-gang naming
|
|
11
|
+
- **v3.5 protocol support** - Added GCM decryption for newer Tuya devices
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- Fixed decryption issue in TuyaDiscovery (utf8 → binary encoding)
|
|
15
|
+
- Fixed multiple connection attempts when using multi-gang accessories
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## 3.2.0 (2026-01-09)
|
|
19
|
+
|
|
20
|
+
### 🎉 New Maintainer
|
|
21
|
+
This plugin is now **homebridge-tuya-community**, a community-maintained fork of the original [homebridge-tuya](https://github.com/iRayanKhan/homebridge-tuya) by [@iRayanKhan](https://github.com/iRayanKhan).
|
|
22
|
+
|
|
23
|
+
Now maintained by [@AxelDreemurr](https://github.com/AxelDreemurr).
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- **Homebridge v2.0 support** - Full compatibility with Homebridge 2.0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## 2.0.1 (2021-03-25)
|
|
30
|
+
This update includes the following changes:
|
|
31
|
+
|
|
32
|
+
[+] Fixes [#233](https://github.com/iRayanKhan/homebridge-tuya/issues/233#issue-833662092), where tempature divisor was not applying, thanks @xortuna [#238](https://github.com/iRayanKhan/homebridge-tuya/pull/238)
|
|
33
|
+
|
|
34
|
+
[!] Note: The next release of this plugin (2.1.0) will change the config to "Tuya", instead of "TuyaLan". No change is needed 'till 2.1.0 is released.
|
|
35
|
+
I am in need of beta testers for 2.1.0 once the next beta goes live, please stay tuned in the homebridge discord server for an announcement.
|
|
36
|
+
|
|
37
|
+
## 2.0.0 (2021-03-12)
|
|
38
|
+
This update includes the following changes:
|
|
39
|
+
|
|
40
|
+
* [+] Verified by Homebridge. [#264](https://github.com/homebridge/verified/issues/264)
|
|
41
|
+
* [!] Note: The next release of this plugin (2.1.0) will change the config to "Tuya", instead of "TuyaLan". No change is needed 'till 2.1.0 is released.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## 1.5.1 (2021-03-02)
|
|
45
|
+
This update includes the following changes:
|
|
46
|
+
|
|
47
|
+
* [+] Fix garage door accessory for Wofea devices, thanks @pelletip [#221](https://github.com/iRayanKhan/homebridge-tuya/pull/221)
|
|
48
|
+
|
|
49
|
+
* [+] Fix log prefix for the following device types: BaseAccessory, RGBTWLight, SimpleBlinds(1), SimpleBlinds2, SimpleFanLight, SimpleHeater, SimpleLight, TuyaAccessory, and ValveAccessory.
|
|
50
|
+
|
|
51
|
+
* [!] Warning: V2.0 will be released once this plugin is verified. The platform name will change from TuyaLan to just Tuya. Please be prepared once V2.0 comes out. No action is required at this time.
|
|
52
|
+
|
|
53
|
+
## 1.5.0 (2021-02-28)
|
|
54
|
+
This update includes the following changes:
|
|
55
|
+
|
|
56
|
+
* Updated dependencies [#215](https://github.com/iRayanKhan/homebridge-tuya/pull/215) + [#216](https://github.com/iRayanKhan/homebridge-tuya/pull/216)
|
|
57
|
+
* Removed plugin prefix from Manufacturer (may have to clear cachedAccessories)
|
|
58
|
+
* Fix crash on launch for garage accessory "ReferenceError: dps is not defined" [#201](https://github.com/iRayanKhan/homebridge-tuya/pull/201) Thanks @longzheng
|
|
59
|
+
* Added dpStatus configuration for Wofea garage door [#202](https://github.com/iRayanKhan/homebridge-tuya/pull/202) Thanks @longzheng
|
|
60
|
+
* Allow more numbers and strings for cmdLow, and cmdHigh [#204](https://github.com/iRayanKhan/homebridge-tuya/pull/204) Thanks @fra-iesus
|
|
61
|
+
* Note: If you have custom logic or support for an unsupported accessory, please open a PR so it can be merged in!
|
|
62
|
+
* Note: Update to Homebridge v1.3.1 to fix "No Response" for TW/RGBTW Lights.
|
|
63
|
+
|
|
64
|
+
## 1.4.0 (2021-02-14)
|
|
65
|
+
Happy Valentines day!
|
|
66
|
+
This update includes the following changes, courtesy of @davidh2075:
|
|
67
|
+
|
|
68
|
+
* CachedAccessories Displayname now sync with the configuration [#196](https://github.com/iRayanKhan/homebridge-tuya/pull/196)
|
|
69
|
+
* Fix for ECONNRESET spam [#197](https://github.com/iRayanKhan/homebridge-tuya/pull/197)
|
|
70
|
+
* Support for Kogan garage door accessory [#198](https://github.com/iRayanKhan/homebridge-tuya/pull/198)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## 1.3.0 (2021-01-25)
|
|
74
|
+
* Added Adaptive Lighting to TW/RGBTW bulbs. Thanks @tom-23 [186]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
## 1.2.0 (2021-01-05)
|
|
78
|
+
* Fix UDP errors in log, thanks @Giocirque [#78]
|
|
79
|
+
* Merged fix for simpleFanLightAccessory DS-03 support, thanks @sholleman [#168]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
## 1.1 (2020-10-28)
|
|
83
|
+
* Added Changelog.md
|
|
84
|
+
* Added Oil Diffuser accessory, thanks @nitaybz (#144)
|
|
85
|
+
* Added Dehumidifier accessory, thanks @fra-iesus (#143)
|
|
86
|
+
* Added AirPurifier accessory, thanks @dhutchison (#139)
|
|
87
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 TuyAPI
|
|
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.
|
package/Readme.MD
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/iRayanKhan/homebridge-tuya/main/assets/Tuya-Plugin-Branding.png" height="100"><br>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
<span align="center">
|
|
7
|
+
|
|
8
|
+
# Homebridge-Tuya
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
</span>
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
Control your supported Tuya accessories locally in HomeKit
|
|
16
|
+
|
|
17
|
+
* [Supported Device Types](#supported-device-types)
|
|
18
|
+
* [Installation Instructions](#installation-instructions)
|
|
19
|
+
* [Configuration](#configuration)
|
|
20
|
+
* [Known Issues](#known-issues)
|
|
21
|
+
* [Troubleshooting](#troubleshooting)
|
|
22
|
+
* [Credits](#credits)
|
|
23
|
+
* [License](#license)
|
|
24
|
+
* [Donating](#donating)
|
|
25
|
+
|
|
26
|
+
## Supported Device Types
|
|
27
|
+
> Click the number next to your device to find the possible DataPoint "DP" values, then add as needed to your config.
|
|
28
|
+
|
|
29
|
+
* Air Conditioner<sup>[1](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types#air-conditioners)</sup>
|
|
30
|
+
* Air Purifiers<sup>[2]()</sup>
|
|
31
|
+
* Convectors<sup>[3](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types#heat-convectors)</sup>
|
|
32
|
+
* Dehumidifers<sup>[4](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types)</sup>
|
|
33
|
+
* Dimmers<sup>[5](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types#simple-dimmers)</sup>
|
|
34
|
+
* Fan<sup>[6](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types)</sup>
|
|
35
|
+
* Fan v2<sup>[7](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types)</sup>
|
|
36
|
+
* Garages<sup>[8](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types#garage-doors)</sup>
|
|
37
|
+
* Heaters<sup>[9](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types)</sup>
|
|
38
|
+
* Lights
|
|
39
|
+
* On/Off<sup>[10](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types)</sup>
|
|
40
|
+
* Brightness<sup>[11](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types#tunable-white-light-bulbs)</sup>
|
|
41
|
+
* Color<sup>[12](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types#white-and-color-light-bulbs)</sup> (Hue, Saturation, Adaptive Lighting)
|
|
42
|
+
* Light Switches (Multi-gang, each gang appears as separate accessory)
|
|
43
|
+
* Sequential (`MultiLight`) - uses DP 1, 2, 3...
|
|
44
|
+
* Custom (`CustomMultiLight`) - specify custom DPs per gang
|
|
45
|
+
* Oil Diffusers<sup>[13](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types)</sup>
|
|
46
|
+
* Outlets<sup>[14](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types#outlets)</sup>
|
|
47
|
+
* Switches<sup>[15](https://github.com/iRayanKhan/homebridge-tuya/wiki/Supported-Device-Types)</sup>
|
|
48
|
+
|
|
49
|
+
Note: Motion, and other sensor types don't behave well with responce requests, so they will not be added.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## Installation Instructions
|
|
53
|
+
|
|
54
|
+
#### Option 1: Install via Homebridge Config UI X:
|
|
55
|
+
|
|
56
|
+
Search for "Tuya" in [homebridge-config-ui-x](https://github.com/oznu/homebridge-config-ui-x) and install `homebridge-tuya-community`.
|
|
57
|
+
|
|
58
|
+
#### Option 2: Manually Install:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
sudo npm install -g homebridge-tuya-community
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
> Homebridge UI
|
|
66
|
+
|
|
67
|
+
1. Navigate to the Plugins page in [homebridge-config-ui-x](https://github.com/oznu/homebridge-config-ui-x).
|
|
68
|
+
2. Click the **Settings** button for the Tuya plugin.
|
|
69
|
+
3. Add your device types
|
|
70
|
+
4. Add device parameters<sup>[10](apple.com/)</sup>
|
|
71
|
+
5. Restart Homebridge or the plugin's child bridge for the changes to take effect.
|
|
72
|
+
|
|
73
|
+
> Manual Configuration
|
|
74
|
+
|
|
75
|
+
1. Edit the config.json file to add your device types, and parameters.
|
|
76
|
+
2. Restart Homebridge or the plugin's child bridge.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
## Known Issues
|
|
80
|
+
|
|
81
|
+
1. If your devices add, but you can't control them, make sure you entered the DataPoint "DP" values for your device.
|
|
82
|
+
|
|
83
|
+
## Troubleshooting
|
|
84
|
+
1. Make sure the plugin is up-to date
|
|
85
|
+
2. Check for existing issues
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Contributing
|
|
89
|
+
|
|
90
|
+
If you have new accessory logic for a new device, please add a function defined by manufacturer, and describe your changes in the Readme file.
|
|
91
|
+
|
|
92
|
+
## Credits
|
|
93
|
+
|
|
94
|
+
* [iRayanKhan](https://github.com/iRayanKhan) - original developer of the [homebridge-tuya](https://github.com/iRayanKhan/homebridge-tuya) plugin.
|
|
95
|
+
* [AMoo-Miki](https://github.com/AMoo-Miki) - developer of the [Tuya-Lan](https://github.com/AMoo-Miki/homebridge-tuya-lan) plugin which this plugin is based off.
|
|
96
|
+
* mxDanger - Plugin branding.
|
|
97
|
+
* [CodeTheWeb](https://github.com/CodeTheWeb) - developer of [TuyaApi](https://github.com/codetheweb/tuyapi), who gratiously provided this repo's name.
|
|
98
|
+
* [Oznu](https://github.com/oznu) - developer of Homebridge, added ```config.schema.json``` , fixed dependencies, and helped inspire this readME off his [gsh](https://github.com/oznu/homebridge-gsh) plugin.
|
|
99
|
+
|
|
Binary file
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const YAML = require('yaml');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const program = require('commander');
|
|
7
|
+
const crypto = require('crypto');
|
|
8
|
+
const readline = require('readline');
|
|
9
|
+
const async = require('async');
|
|
10
|
+
|
|
11
|
+
let file;
|
|
12
|
+
|
|
13
|
+
program
|
|
14
|
+
.name('tuya-lan decode')
|
|
15
|
+
.option('--key <key>', 'device key')
|
|
16
|
+
.option('--use <version>', 'override version string', '3.3')
|
|
17
|
+
.arguments('<file>')
|
|
18
|
+
.action(loc => {
|
|
19
|
+
file = loc;
|
|
20
|
+
})
|
|
21
|
+
.parse(process.argv);
|
|
22
|
+
|
|
23
|
+
const crc32LookupTable = [];
|
|
24
|
+
(() => {
|
|
25
|
+
for (let i = 0; i < 256; i++) {
|
|
26
|
+
let crc = i;
|
|
27
|
+
for (let j = 8; j > 0; j--) crc = (crc & 1) ? (crc >>> 1) ^ 3988292384 : crc >>> 1;
|
|
28
|
+
crc32LookupTable.push(crc);
|
|
29
|
+
}
|
|
30
|
+
})();
|
|
31
|
+
|
|
32
|
+
const getCRC32 = buffer => {
|
|
33
|
+
let crc = 0xffffffff;
|
|
34
|
+
for (let i = 0, len = buffer.length; i < len; i++) crc = crc32LookupTable[buffer[i] ^ (crc & 0xff)] ^ (crc >>> 8);
|
|
35
|
+
return ~crc;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const decodeLine = (key, input, log = true) => {
|
|
39
|
+
const encoding = (input.substr(0, 8) === '000055aa') ? 'hex' : 'base64';
|
|
40
|
+
|
|
41
|
+
let buffer = Buffer.from(input, encoding);
|
|
42
|
+
const raw = Buffer.from(input, encoding);
|
|
43
|
+
const len = buffer.length;
|
|
44
|
+
if (buffer.readUInt32BE(0) !== 0x000055aa || buffer.readUInt32BE(len - 4) !== 0x0000aa55) {
|
|
45
|
+
console.log("*** Input doesn't match the expected signature:", buffer.readUInt32BE(0).toString(16).padStart(8, '0'), buffer.readUInt32BE(len - 4).toString(16).padStart(8, '0'));
|
|
46
|
+
return rl.prompt();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Try 3.3
|
|
50
|
+
const size = buffer.readUInt32BE(12);
|
|
51
|
+
const cmd = buffer.readUInt32BE(8);
|
|
52
|
+
const seq = buffer.readUInt32BE(4);
|
|
53
|
+
const crcIn = buffer.readInt32BE(len - 8);
|
|
54
|
+
const preHash = buffer.slice(0, len - 8);
|
|
55
|
+
if (log) {
|
|
56
|
+
console.log(`Cmd > ${cmd} \tLen > ${len}\tSize > ${size}\tSeq > ${seq}`);
|
|
57
|
+
console.log(`CRC > \t${crcIn === getCRC32(preHash) ? 'Pass' : `Fail ${crcIn} ≠ ${getCRC32(preHash)}`}`);
|
|
58
|
+
}
|
|
59
|
+
const flag = buffer.readUInt32BE(16) & 0xFFFFFF00;
|
|
60
|
+
buffer = buffer.slice(len - size + (flag ? 0 : 4), len - 8);
|
|
61
|
+
if (buffer.indexOf(program.use || '3.3') !== -1) buffer = buffer.slice(15 + buffer.indexOf(program.use || '3.3'));
|
|
62
|
+
else if (buffer.indexOf('3.2') !== -1) buffer = buffer.slice(15 + buffer.indexOf('3.2'));
|
|
63
|
+
|
|
64
|
+
switch (cmd) {
|
|
65
|
+
case 7:
|
|
66
|
+
case 8:
|
|
67
|
+
case 10:
|
|
68
|
+
case 13:
|
|
69
|
+
case 16:
|
|
70
|
+
if (buffer.length === 0) {
|
|
71
|
+
console.log(`${('' + seq).padEnd(4)} Decoded ${cmd}> Empty`);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const decipher = crypto.createDecipheriv('aes-128-ecb', key, '');
|
|
76
|
+
let decryptedMsg = decipher.update(buffer, 'buffer', 'utf8');
|
|
77
|
+
decryptedMsg += decipher.final('utf8');
|
|
78
|
+
|
|
79
|
+
console.log(`${('' + seq).padEnd(4)} Decoded ${cmd}>`, decryptedMsg);
|
|
80
|
+
if (log) console.log(`${('' + seq).padEnd(4)} Raw ${cmd}>`, raw.toString('hex'));
|
|
81
|
+
} catch (ex) {
|
|
82
|
+
console.log(`${('' + seq).padEnd(4)}*Failed ${cmd}>`, raw.toString('hex'));
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
|
|
86
|
+
case 9:
|
|
87
|
+
console.log(`${('' + seq).padEnd(4)} Decoded ${cmd}>`, flag ? 'Ping' : 'Pong');
|
|
88
|
+
break;
|
|
89
|
+
|
|
90
|
+
case 19:
|
|
91
|
+
let decryptedMsg;
|
|
92
|
+
try {
|
|
93
|
+
const decipher = crypto.createDecipheriv('aes-128-ecb', key, '');
|
|
94
|
+
decryptedMsg = decipher.update(buffer, 'buffer', 'utf8');
|
|
95
|
+
decryptedMsg += decipher.final('utf8');
|
|
96
|
+
} catch (ex) {
|
|
97
|
+
decryptedMsg = '';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!decryptedMsg) {
|
|
101
|
+
try {
|
|
102
|
+
const decipher = crypto.createDecipheriv('aes-128-ecb', Buffer.from('6c1ec8e2bb9bb59ab50b0daf649b410a', 'hex'), '');
|
|
103
|
+
decryptedMsg = decipher.update(buffer, 'buffer', 'utf8');
|
|
104
|
+
decryptedMsg += decipher.final('utf8');
|
|
105
|
+
} catch (ex) {
|
|
106
|
+
decryptedMsg = '';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!decryptedMsg) decryptedMsg = buffer.toString('utf8');
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
JSON.parse(decryptedMsg);
|
|
114
|
+
console.log(`${('' + seq).padEnd(4)} Decoded ${cmd}>`, decryptedMsg);
|
|
115
|
+
if (log) console.log(`${('' + seq).padEnd(4)} Raw ${cmd}>`, raw.toString('hex'));
|
|
116
|
+
} catch (ex) {
|
|
117
|
+
console.log(`${('' + seq).padEnd(4)}*Failed ${cmd}>`, raw.toString('hex'));
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
|
|
121
|
+
default:
|
|
122
|
+
console.log(`Unknown ${cmd}>`, raw.toString('hex'));
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
async.auto({
|
|
127
|
+
Key: next => {
|
|
128
|
+
if (program.key) return next(null, program.key);
|
|
129
|
+
|
|
130
|
+
const rl = readline.createInterface({
|
|
131
|
+
input: process.stdin,
|
|
132
|
+
output: process.stdout,
|
|
133
|
+
prompt: '\nEnter the device key: ',
|
|
134
|
+
crlfDelay: Infinity
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
rl.prompt();
|
|
138
|
+
|
|
139
|
+
rl.on('line', line => {
|
|
140
|
+
const input = line.trim();
|
|
141
|
+
if (!input) return rl.prompt();
|
|
142
|
+
|
|
143
|
+
rl.close();
|
|
144
|
+
next(null, input);
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
File: ['Key', (data, next) => {
|
|
148
|
+
if (!file) return next();
|
|
149
|
+
let content;
|
|
150
|
+
try {
|
|
151
|
+
content = fs.readFileSync(path.resolve(file), 'utf8');
|
|
152
|
+
} catch (ex) {
|
|
153
|
+
console.error('Filed to read the file');
|
|
154
|
+
console.log(ex);
|
|
155
|
+
return next(true);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const packets = YAML.parseDocument(content);
|
|
159
|
+
if (Array.isArray(packets.errors) && packets.errors.length > 0) {
|
|
160
|
+
packets.errors.forEach(console.error);
|
|
161
|
+
return next(true);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const rows = packets.toJSON();
|
|
165
|
+
|
|
166
|
+
Object.keys(rows).forEach(key => {
|
|
167
|
+
decodeLine(data.Key, rows[key].replace(/\n/g, ''), false);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
next();
|
|
171
|
+
}],
|
|
172
|
+
Line: ['File', (data, next) => {
|
|
173
|
+
if (file) return next();
|
|
174
|
+
|
|
175
|
+
console.log('\n\n*** Hit Ctrl+C or key in "exit" to end ***');
|
|
176
|
+
|
|
177
|
+
const rl = readline.createInterface({
|
|
178
|
+
input: process.stdin,
|
|
179
|
+
output: process.stdout,
|
|
180
|
+
prompt: '\nEnter the encrypted message: ',
|
|
181
|
+
crlfDelay: Infinity
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
rl.prompt();
|
|
185
|
+
|
|
186
|
+
rl.on('line', line => {
|
|
187
|
+
const input = line.trim();
|
|
188
|
+
if (input.toLowerCase() === 'exit') process.exit(0);
|
|
189
|
+
|
|
190
|
+
decodeLine(data.Key, input);
|
|
191
|
+
|
|
192
|
+
rl.prompt();
|
|
193
|
+
}).on('close', () => {
|
|
194
|
+
process.exit(0);
|
|
195
|
+
});
|
|
196
|
+
}]
|
|
197
|
+
});
|