mirror of
https://github.com/lehanspb/tuya-mqtt.git
synced 2025-12-18 16:17:30 +00:00
Compare commits
16 Commits
dependabot
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de14f71616 | ||
|
|
adb59a0d9d | ||
|
|
f865e259a1 | ||
|
|
4ea2f0a58f | ||
|
|
f3d0d0602e | ||
|
|
bb97e731a9 | ||
|
|
9a9a314d14 | ||
|
|
9080a41d9a | ||
|
|
f6bd28c41a | ||
|
|
1d1ab0d62a | ||
|
|
a170287e9e | ||
|
|
47734e03d0 | ||
|
|
eb800133a0 | ||
|
|
6aded16979 | ||
|
|
7cc3d1d5a6 | ||
|
|
59d1131db5 |
19
CHANGELOG.md
19
CHANGELOG.md
@@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [3.1.5]
|
||||
### Added
|
||||
- Added support of friendly names for the subDevices behind gateway (processDpsKeyWcidNameCommand)
|
||||
|
||||
### Changed
|
||||
- Functions publishTopics and publishDpsTopics now can publish subDevice's friendly name to MQTT
|
||||
|
||||
|
||||
## [3.1.0]
|
||||
Forked from https://github.com/TheAgentK/tuya-mqtt
|
||||
### Added
|
||||
- Added support for Zigdee subdevices for Tuya Wireless Gateway
|
||||
- Added new dp-refresh funtion according to tuyapi documentation
|
||||
- Command and state topics for DPS keys for subdevices
|
||||
|
||||
### Changed
|
||||
- Updated some libraries to latest version
|
||||
|
||||
|
||||
## [3.0.0]
|
||||
The 3.0.0 release is a major refactor of the project with significant changes from previous version. Only major additions and changes are listed below.
|
||||
### Added
|
||||
|
||||
126
README.md
126
README.md
@@ -1,21 +1,21 @@
|
||||
# tuya-mqtt
|
||||
|
||||
# !!!! Important Note !!!!
|
||||
This project is currently in maintainance mode. No further enhancements to this project are planned and will not be planned for the future unless someone out there is interested in becoming the new maintainer. Please do not open issues to request new features, new device support, etc, as they will likely be closed with no comment. I will try to support existing functionality, but even this will likely be on a very limited basis. If you are interested in maintaining this project, please post [here](https://github.com/rospogrigio/localtuya/issues/194).
|
||||
# Note
|
||||
|
||||
I have decided to step away from this project as I've made the personal decision to rid myself of any Tuya Wifi based devices (I'm down to only 4 at this point, and they are all easy to replace or at least flash with Tasmota). This decision was made due to the fact that Tuya continues to make it more and more difficult to control their devices locally. While I don't blame them for this, these devices were only interesting to me because of this local control and thus I can no longer meet my personal goals with Tuya devices (at least the Wifi ones) so I will no longer be purchasing/using them going forward.
|
||||
I'm not a developer and I'm new to nodejs.
|
||||
|
||||
I just need to get data from Zigbee devices behind Tuya Wireless Gateway and the ability to control them using MQTT commands.
|
||||
|
||||
I forked this repository [TheAgentK](https://github.com/TheAgentK/tuya-mqtt) and made some changes.
|
||||
|
||||
# About
|
||||
This project is a bridge that allows locally controlling IOT devices manufactured by Tuya Inc., and sold under many different brands, via simple MQTT topics. It effectively translate the Tuya protocol to easy to use topics.
|
||||
This project is a bridge that allows locally controlling IOT devices manufactured by Tuya Inc., and sold under many different brands, via simple MQTT topics. It effectively translate the Tuya protocol to easy to use topics.
|
||||
|
||||
Using this script requires obtaining the device ID and local keys for each of your devices after they are configured via the Tuya/Smart Life or other Tuya compatible app (there are many). With this information it is possible to communicate locally with Tuya devices using Tuya protocol version 3.1 and 3.3 without using the Tuya Cloud service, however, getting the keys requires signing up for a Tuya IOT developer account or using one of several other alternative methods (such as dumping the memory of a Tuya based app running on Android).
|
||||
Using this script requires obtaining the device ID and local keys for each of your devices after they are configured via the Tuya/Smart Life or other Tuya compatible app (there are many). With this information it is possible to communicate locally with Tuya devices using Tuya protocol version 3.1 and 3.3 without using the Tuya Cloud service, however, getting the keys requires signing up for a Tuya IOT developer account or using one of several other alternative methods (such as dumping the memory of a Tuya based app running on Android).
|
||||
|
||||
To acquire keys for your device please see the instructions at the TuyAPI project (on which this script is based) available at the [TuyAPI GitHub site](https://github.com/codetheweb/tuyapi/blob/master/docs/SETUP.md).
|
||||
|
||||
**Acquiring device keys is outside the scope of this project!** Issues opened regarding acquiring keys will likely be closed without comment. Please verify that your device can be queried and controlled via tuya-cli before opening any issue. If your device can't be controlled by tuya-cli then it cannot be used with this project.
|
||||
|
||||
**!!!!!!!!!! Important information regarding the 3.0 release !!!!!!!!!!**\
|
||||
The 3.0.0 release (Oct 17th, 2020) is a major refactor of the tuya-mqtt project and, as such, is a breaking release for all users of previous versions. Almost everything about the project is different, including configuration method, topic names, etc. Upgrading users should carefully read the instructions below and assume they are starting over from scratch.
|
||||
**Acquiring device keys is outside the scope of this project!** Issues opened regarding acquiring keys will likely be closed without comment. Please verify that your device can be queried and controlled via tuya-cli before opening any issue. If your device can't be controlled by tuya-cli then it cannot be used with this project.
|
||||
|
||||
## Installation
|
||||
Download this project to your system into any directory (example below uses /opt/tuya-mqtt) and install tuyapi from the same folder that the tuya-mqtt.js is in
|
||||
@@ -24,7 +24,7 @@ Download this project to your system into any directory (example below uses /opt
|
||||
cd /opt
|
||||
|
||||
// clone this project
|
||||
git clone https://github.com/TheAgentK/tuya-mqtt
|
||||
git clone https://github.com/lehanspb/tuya-mqtt
|
||||
|
||||
// change directory to the project directory
|
||||
cd tuya-mqtt
|
||||
@@ -51,19 +51,33 @@ If you use the "tuya-cli wizard" method to acquire your device keys you can leve
|
||||
[
|
||||
{
|
||||
name: 'Tuya Device 1',
|
||||
version: '3.3',
|
||||
ip: '192.168.20.251',
|
||||
id: '86435357d8b123456789',
|
||||
key: '8b2a69c9876543210'
|
||||
},
|
||||
{
|
||||
name: 'Tuya Device 2',
|
||||
version: '3.3',
|
||||
ip: '192.168.20.252',
|
||||
id: 'eb532eea7d12345678abc',
|
||||
key: '899810012345678'
|
||||
key: '899810012345678',
|
||||
subDevices:
|
||||
[ { name: 'subdevice1',
|
||||
id: 'zt431eda8d12345678awc',
|
||||
cid: '1a24fkfffe6b4e24'
|
||||
},
|
||||
{ name: 'subdevice1',
|
||||
id: 'rb737qea7v15342678aq3',
|
||||
cid: '1a24fkfffe0t2c29'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
Note that, because the format is JSON5, which is a superset of JSON, you can use standard, strict JSON syntax, or the more forgiving JSON5 format, or even mix and match in the same file.
|
||||
|
||||
By default tuya-mqtt will attempt to find the device and automatically detect the Tuya protocol version, however, this only works if the system running tuya-mqtt is on the same network/subnet as the devices being controlled. If this is not the case, or if automatic detection fails for some other reason, it is possible to specify the IP address and protocol manually by adding the "ip:" property to the devices.conf file. Note that if the IP address is specified manually it is required to also manually specify the protocol version using the "version:" parameter as either "3.1" or "3.3". The easiest way to determine the protocol version is to try controlling the device with tuya-cli and try each version to see which one works.
|
||||
By default tuya-mqtt will attempt to find the device and automatically detect the Tuya protocol version, however, this only works if the system running tuya-mqtt is on the same network/subnet as the devices being controlled. If this is not the case, or if automatic detection fails for some other reason, it is possible to specify the IP address and protocol manually by adding the "ip:" property to the devices.conf file. Note that if the IP address is specified manually it is required to also manually specify the protocol version using the "version:" parameter as either "3.1" or "3.3". The easiest way to determine the protocol version is to try controlling the device with tuya-cli and try each version to see which one works.
|
||||
|
||||
While the above syntax may be enough to create a working tuya-mqtt install with raw DPS values accessible via DPS topics, the full functionality of tuya-mqtt 3.0 is only unlocked by configuring device types to get. Please see the full [DEVICES](docs/DEVICES.md) documentation for details.
|
||||
|
||||
@@ -74,8 +88,41 @@ node tuya-mqtt.js
|
||||
To enable debugging output (required when opening an issue):
|
||||
```
|
||||
DEBUG=tuya-mqtt:* tuya-mqtt.js
|
||||
or
|
||||
DEBUG=* tuya-mqtt.js
|
||||
for full debugging
|
||||
```
|
||||
|
||||
### Systemd script for Debian-like OS
|
||||
|
||||
Just create file /etc/systemd/system/tuya-mqtt.service
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=tuya-mqtt
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/node /opt/tuya-mqtt/tuya-mqtt.js
|
||||
Restart=always
|
||||
User=openhab
|
||||
Group=openhab
|
||||
Environment=PATH=/usr/bin/
|
||||
Environment=NODE_ENV=production
|
||||
WorkingDirectory=/opt/tuya-mqtt/
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
```
|
||||
|
||||
Enable and run:
|
||||
```
|
||||
systemctl enable tuya-mqtt.service
|
||||
systemctl start tuya-mqtt
|
||||
```
|
||||
|
||||
|
||||
### Updating devices.conf with new and/or changed devices:
|
||||
After adding or changing devices to your Tuya account the devices.conf file can be automatically updated with all new devices and name/key changes by using the merge-devices.js script. Create a file named new-devices.conf with the new "tuya-cli wizard" output then run ```node merge-devices.js```. A dated backup of the original devices.conf file will be created automatically before changes are made. Devices are only added and updated, never removed. The resulting devices.conf file will be neatly formatted and sorted alphabetically by device name.
|
||||
|
||||
@@ -117,16 +164,16 @@ Another advantage of friendly topics is that not all devices respond to schema r
|
||||
For more details on using friendly topics, please read the [DEVICES](docs/DEVICES.md) documentation which discusses how to configure supported devices or define a custom template.
|
||||
|
||||
## DPS Topics
|
||||
Controlling devices directly via DPS topics requires enough knowledge of the device to know which topics accept what values. Described below are two different methods for interfacing with DPS values, the JSON DPS topic, and the individual DPS key topics.
|
||||
Controlling devices directly via DPS topics requires enough knowledge of the device to know which topics accept what values. Described below are two different methods for interfacing with DPS values, the JSON DPS topic, and the individual DPS key topics.
|
||||
|
||||
### DPS JSON topic
|
||||
The JSON DPS topic allows controlling Tuya devices by sending Tuya native style JSON messages to the command topic, and by monitoring for Tuya style JSON replies on the state topic. You can get more details on this format by reading the [TuyAPI documentation](https://codetheweb.github.io/tuyapi/index.html), but, for example, to turn off a dimmer switch you could issue a MQTT message containing the JSON value ```{dps: 1, set: false}``` to the DPS/command topic for the device. If you wanted to turn the dimmer on, and set brightness to 50%, you could issue separate messages ```{dps: 1, set: true}``` and then ```{dps: 2, set: 128}```, or, the Tuya JSON protocol also allows setting multiple values in a single set command using the format ```{'multiple': true, 'data': {'1': true, '2': 128}}```. JSON state and commands should use the DPS/state and DPS/command topics respectively. Below is an example of the topics:
|
||||
The JSON DPS topic allows controlling Tuya devices by sending Tuya native style JSON messages to the command topic, and by monitoring for Tuya style JSON replies on the state topic. You can get more details on this format by reading the [TuyAPI documentation](https://codetheweb.github.io/tuyapi/index.html), but, for example, to turn off a dimmer switch you could issue a MQTT message containing the JSON value ```{dps: 1, set: false}``` to the DPS/command topic for the device. If you wanted to turn the dimmer on, and set brightness to 50%, you could issue separate messages ```{dps: 1, set: true}``` and then ```{dps: 2, set: 128}```, or, the Tuya JSON protocol also allows setting multiple values in a single set command using the format ```{'multiple': true, 'data': {'1': true, '2': 128}}```. JSON state and commands should use the DPS/state and DPS/command topics respectively. Below is an example of the topics:
|
||||
```
|
||||
tuya/dimmer_device/DPS/state
|
||||
tuya/dimmer_device/DPS/command
|
||||
```
|
||||
### DPS Key topics
|
||||
In addition to the JSON DPS topic, it's also possible to use the DPS key topics. DPS key topics allow you to monitor and send simple bool/number/string values directly to DPS keys without having to use the Tuya JSON format, the conversion to Tuya JSON is handled by tuya-mqtt. Using the example from above, turning on the dimmer and setting brightness to 50% you would simply issue the message "true" to DPS/1/command and the message "128" to DPS/2/command.
|
||||
In addition to the JSON DPS topic, it's also possible to use the DPS key topics. DPS key topics allow you to monitor and send simple bool/number/string values directly to DPS keys without having to use the Tuya JSON format, the conversion to Tuya JSON is handled by tuya-mqtt. Using the example from above, turning on the dimmer and setting brightness to 50% you would simply issue the message "true" to DPS/1/command and the message "128" to DPS/2/command.
|
||||
```
|
||||
tuya/dimmer_device/DPS/1/state --> true/false for on/off state
|
||||
tuya/dimmer_device/DPS/2/command <-- 1-255 for brightness state
|
||||
@@ -136,26 +183,49 @@ tuya/dimmer_device/DPS/2/command <-- accepts 1-255 for controlling brightness l
|
||||
**!!! Important Note !!!**
|
||||
When sending commands directly to DPS values there are no limitation on what values are sent as tuya-mqtt has no way to know what are valid vs invalid for any given DPS key. Sending values that are out-of-range or of different types than the DPS key expects can cause unpredictable behavior of your device, from causing timeouts, to reboots, to hanging the device. While I've never seen a device fail to recover after a restart, please keep this in mind when sending commands to your device.
|
||||
|
||||
## DPS Topics for devices behind Tuya Gateway
|
||||
In addition to the DPS Key topics, it's possible to use the DPS for devices behind Tuya Gateway.
|
||||
'cid' - is the subdevice id.
|
||||
'cidname' - is the name of subdevice (from devices.conf)
|
||||
|
||||
This example demostrates DPS values and commands for Tuya Smart Thermostat Radiator Valve behind Tuya Gateway:
|
||||
|
||||
```
|
||||
Thermostat mode:
|
||||
tuya/zgw1/thermostat/dsp/4/state --> {"4":"auto"}
|
||||
Possible values: auto/temp_auto/holiday/manual/comfort/eco/BOOST
|
||||
tuya/zgw1/thermostat/dps/4/command <-- auto
|
||||
|
||||
Temperature Setpoint:
|
||||
tuya/zgw1/thermostat/dps/2/state --> {"2": 220}
|
||||
Where 220 - 22.0 Celsius
|
||||
tuya/zgw1/thermostat/dps/command <-- 225
|
||||
|
||||
Current Temperature:
|
||||
tuya/zgw1/thermostat/dps/3/state --> {"3": 225}
|
||||
Where 225 - 22.5 Celsius
|
||||
|
||||
Valve percent:
|
||||
tuya/zgw1/thermostat/dps/109/state --> {"109": 30}
|
||||
Where 30 - 30%
|
||||
```
|
||||
|
||||
You can also use JSON commands with 'cid'
|
||||
|
||||
```
|
||||
tuya/zgw1/dps/command <-- {"dps": 2, "set": 225, "cid": "2c34f13fde594a34"}
|
||||
```
|
||||
|
||||
## Issues
|
||||
Not all Tuya protocols are supported. For example, some devices use protocol 3.2 which currently remains unsupported by the TuyAPI project due to lack of enough information to reverse engineer the protocol. If you are unable to control your devices with tuya-mqtt please verify that you can query and control them with tuya-cli first. If tuya-cli works, then this script should also work, if it doesn't then this script will not work either.
|
||||
|
||||
## Integration with other Home Automation tools
|
||||
openHAB examples are [here](docs/openHAB.md).
|
||||
## Integration with openHAB
|
||||
openHAB 3.x examples are [here](docs/openHAB.md).
|
||||
|
||||
## Contributors
|
||||
- [TheAgentK](https://github.com/TheAgentK)
|
||||
- [tsightler](https://github.com/tsightler)
|
||||
- [Tycale](https://github.com/Tycale)
|
||||
- [crashdummymch](https://github.com/crashdummymch)
|
||||
- [GadgetAngel](https://github.com/GadgetAngel)
|
||||
- [dkrahmer](https://github.com/dkrahmer)
|
||||
- [lehanspb](https://github.com/lehanspb)
|
||||
|
||||
## Related Projects:
|
||||
- https://github.com/codetheweb/tuyapi
|
||||
- https://github.com/unparagoned/njsTuya
|
||||
- https://github.com/clach04/python-tuya
|
||||
- https://github.com/Marcus-L/m4rcus.TuyaCore
|
||||
- Specs: https://docs.tuya.com/en/cloudapi/cloud_access.html
|
||||
|
||||
[](https://forthebadge.com)
|
||||
[](https://forthebadge.com)
|
||||
|
||||
@@ -11,13 +11,14 @@ class TuyaDevice {
|
||||
this.config = deviceInfo.configDevice
|
||||
this.mqttClient = deviceInfo.mqttClient
|
||||
this.topic = deviceInfo.topic
|
||||
|
||||
|
||||
// Build TuyAPI device options from device config info
|
||||
this.options = {
|
||||
id: this.config.id,
|
||||
key: this.config.key
|
||||
}
|
||||
if (this.config.name) { this.options.name = this.config.name.toLowerCase().replace(/\s|\+|#|\//g,'_') }
|
||||
|
||||
if (this.config.ip) {
|
||||
this.options.ip = this.config.ip
|
||||
if (this.config.version) {
|
||||
@@ -27,6 +28,9 @@ class TuyaDevice {
|
||||
}
|
||||
}
|
||||
|
||||
debug(' ############ Config ', JSON.stringify(this.config))
|
||||
debug(' ############ Options ', JSON.stringify(this.options))
|
||||
|
||||
// Set default device data for Home Assistant device registry
|
||||
// Values may be overridden by individual devices
|
||||
this.deviceData = {
|
||||
@@ -37,6 +41,7 @@ class TuyaDevice {
|
||||
|
||||
// Initialize properties to hold cached device state data
|
||||
this.dps = {}
|
||||
this.cid = {}
|
||||
this.color = {'h': 0, 's': 0, 'b': 0}
|
||||
|
||||
// Device friendly topics
|
||||
@@ -56,10 +61,31 @@ class TuyaDevice {
|
||||
// Create the new Tuya Device
|
||||
this.device = new TuyAPI(JSON.parse(JSON.stringify(this.options)))
|
||||
|
||||
this.device.on('dp-refresh', (data) => {
|
||||
if (typeof data === 'object') {
|
||||
if (data.cid) {
|
||||
debug('Received dp-refresh data from device '+this.options.id+' cid: '+data.cid+' ->', JSON.stringify(data.dps))
|
||||
} else {
|
||||
debug('Received dp-refresh data from device '+this.options.id+' ->', JSON.stringify(data.dps))
|
||||
debug('Received dp-refresh data from device '+this.options.id+' ->', JSON.stringify(data))
|
||||
}
|
||||
this.updateState(data)
|
||||
} else {
|
||||
if (data !== 'json obj data unvalid') {
|
||||
debug('Received string data from device '+this.options.id+' ->', data.replace(/[^a-zA-Z0-9 ]/g, ''))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Listen for device data and call update DPS function if valid
|
||||
this.device.on('data', (data) => {
|
||||
if (typeof data === 'object') {
|
||||
debug('Received JSON data from device '+this.options.id+' ->', JSON.stringify(data.dps))
|
||||
if (data.cid) {
|
||||
debug('Received JSON data from device '+this.options.id+' cid: '+data.cid+' ->', JSON.stringify(data.dps))
|
||||
} else {
|
||||
debug('Received JSON data from device '+this.options.id+' ->', JSON.stringify(data.dps))
|
||||
debug('Received JSON data from device '+this.options.id+' ->', JSON.stringify(data))
|
||||
}
|
||||
this.updateState(data)
|
||||
} else {
|
||||
if (data !== 'json obj data unvalid') {
|
||||
@@ -148,16 +174,27 @@ class TuyaDevice {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.connected) {
|
||||
this.publishTopics()
|
||||
}
|
||||
let cid = data.cid
|
||||
this.cid = cid
|
||||
|
||||
// Had to comment this out 2024.02.19
|
||||
// New Tuya multimode gateway (zigbee & ble) don't send connected state from BLE-devices
|
||||
// if (this.connected) {
|
||||
// this.publishTopics()
|
||||
// }
|
||||
this.publishTopics()
|
||||
} else {
|
||||
debug('Could not updateState ' + JSON.stringify(data))
|
||||
}
|
||||
}
|
||||
|
||||
// Publish device specific state topics
|
||||
publishTopics() {
|
||||
// Don't publish if device is not connected
|
||||
if (!this.connected) return
|
||||
|
||||
// Had to comment it out 2024.02.19
|
||||
// New Tuya multimode gateway (zigbee & ble) don't send connected state from BLE-devices
|
||||
// if (!this.connected) return
|
||||
|
||||
// Loop through and publish all device specific topics
|
||||
for (let topic in this.deviceTopics) {
|
||||
@@ -167,7 +204,14 @@ class TuyaDevice {
|
||||
if (this.dps[key] && this.dps[key].updated) {
|
||||
const state = this.getTopicState(deviceTopic, this.dps[key].val)
|
||||
if (state) {
|
||||
this.publishMqtt(this.baseTopic + topic, state, true)
|
||||
if (this.cid) {
|
||||
// this.publishMqtt(this.baseTopic + cid + '/' + topic, state, true)
|
||||
// Change cid to cidname
|
||||
let cidname = this.config.subDevices.find(el => el.cid === this.cid);
|
||||
this.publishMqtt(this.baseTopic + cidname.name + '/' + topic, state, true)
|
||||
} else {
|
||||
this.publishMqtt(this.baseTopic + topic, state, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,7 +225,18 @@ class TuyaDevice {
|
||||
try {
|
||||
if (!Object.keys(this.dps).length) { return }
|
||||
|
||||
const dpsTopic = this.baseTopic + 'dps'
|
||||
let dpsTopic
|
||||
if (this.cid) {
|
||||
// dpsTopic = this.baseTopic + this.cid + '/dps'
|
||||
// Change cid to cidname
|
||||
let cidname = this.config.subDevices.find(el => el.cid === this.cid);
|
||||
dpsTopic = this.baseTopic + cidname.name + '/dps'
|
||||
} else {
|
||||
dpsTopic = this.baseTopic + 'dps'
|
||||
}
|
||||
|
||||
// const dpsTopic = this.baseTopic + 'dps'
|
||||
|
||||
// Publish DPS JSON data if not empty
|
||||
let data = {}
|
||||
for (let key in this.dps) {
|
||||
@@ -196,6 +251,7 @@ class TuyaDevice {
|
||||
this.publishMqtt(dpsStateTopic, data, false)
|
||||
|
||||
// Publish dps/<#>/state value for each device DPS
|
||||
// or cid/dps/<#>/state if cid exists
|
||||
for (let key in this.dps) {
|
||||
// Only publish values if different from previous value
|
||||
if (this.dps[key].updated) {
|
||||
@@ -289,7 +345,7 @@ class TuyaDevice {
|
||||
const deviceTopic = this.deviceTopics.hasOwnProperty(stateTopic) ? this.deviceTopics[stateTopic] : ''
|
||||
|
||||
if (deviceTopic) {
|
||||
debugCommand('Device '+this.options.id+' received command topic: '+commandTopic+', message: '+command)
|
||||
// debugCommand('Device '+this.options.id+' received command topic: '+commandTopic+', message: '+command)
|
||||
let commandResult = this.sendTuyaCommand(command, deviceTopic)
|
||||
if (!commandResult) {
|
||||
debugCommand('Command topic '+this.baseTopic+commandTopic+' received invalid value: '+command)
|
||||
@@ -326,6 +382,24 @@ class TuyaDevice {
|
||||
}
|
||||
}
|
||||
|
||||
processDpsKeyWcidNameCommand(message, subDevDpsKey, cidName) {
|
||||
if (utils.isJsonString(message)) {
|
||||
debugCommand('Individual DPS command topics do not accept JSON values')
|
||||
} else {
|
||||
const dpsMessage = this.parseDpsMessage(message)
|
||||
let subdev = this.config.subDevices.find(el => el.name === cidName);
|
||||
const sdcid = subdev.cid
|
||||
debugCommand('Received command for '+sdcid+' DPS'+subDevDpsKey+': ', message)
|
||||
const command = {
|
||||
dps: subDevDpsKey,
|
||||
set: dpsMessage,
|
||||
cid: sdcid
|
||||
}
|
||||
this.set(command)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Parse string message into boolean and number types
|
||||
parseDpsMessage(message) {
|
||||
if (typeof message === 'boolean' ) {
|
||||
|
||||
301
docs/openHAB.md
301
docs/openHAB.md
@@ -1,142 +1,217 @@
|
||||
:exclamation: There is a greate Step-By-Step guide from user HolgiHab at openhab community ([Step-By-Step Guide](
|
||||
https://community.openhab.org/t/step-by-step-guide-for-adding-tuya-bulbs-smart-life-to-oh2-using-tuya-mqtt-js-by-agentk/59371)). This guide is not only for light bulbs, but also applies to sockets. :exclamation:
|
||||
## Example items for OpenHAB 3.x Bindings
|
||||
|
||||
## Example items for OpenHAB 1.x Bindings (still works with OH > 2.4 but only if legacy 1.x MQTT bindings are enabled)
|
||||
### simple switch on/off
|
||||
### Tuya Smart Thermostat Radiator Valve behind Tuya Gateway
|
||||
|
||||
### Things channels (configured via web):
|
||||
|
||||
#### Thermostat mode:
|
||||
Channel identifier:
|
||||
```
|
||||
mode
|
||||
```
|
||||
|
||||
Switch tuya_kitchen_coffeemachine_mqtt "Steckdose Kaffeemaschine" <socket> (<GROUPS>) ["Switchable"] {
|
||||
mqtt="<[broker:tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/state:state:default:.*],
|
||||
>[broker:tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/command/on:command:ON:true],
|
||||
>[broker:tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/command/off:command:OFF:false]"
|
||||
State:
|
||||
```
|
||||
tuya/zgw1/1a24fkfffe6b4e24/dsp/4/state
|
||||
```
|
||||
Example output: {"4":"auto"}
|
||||
Possible values: auto/temp_auto/holiday/manual/comfort/eco/BOOST
|
||||
|
||||
|
||||
Command:
|
||||
```
|
||||
tuya/zgw1/dps/command
|
||||
```
|
||||
|
||||
Outgoing Value Format:
|
||||
```
|
||||
{"dps": 4, "set": "%s", "cid": "1a24fkfffe6b4e24"}
|
||||
```
|
||||
|
||||
#### Temperature Setpoint
|
||||
Channel identifier:
|
||||
```
|
||||
setpoint
|
||||
```
|
||||
|
||||
State:
|
||||
```
|
||||
tuya/zgw1/1a24fkfffe6b4e24/dsp/2/state
|
||||
```
|
||||
Example output: {"2": 220}
|
||||
|
||||
Command:
|
||||
```
|
||||
tuya/zgw1/dps/command
|
||||
```
|
||||
|
||||
Incoming Value Transformations:
|
||||
```
|
||||
JS:tuya-in.js
|
||||
```
|
||||
|
||||
Outgoing Value Transformation:
|
||||
```
|
||||
JS:tuya-out.js
|
||||
```
|
||||
|
||||
Outgoing Value Format:
|
||||
```
|
||||
{"dps": 2, "set": "%s", "cid": "1a24fkfffe6b4e24"}
|
||||
```
|
||||
|
||||
#### Current Temperature
|
||||
Channel identifier:
|
||||
```
|
||||
temperature
|
||||
```
|
||||
|
||||
State:
|
||||
```
|
||||
tuya/zgw1/1a24fkfffe6b4e24/dsp/3/state
|
||||
```
|
||||
|
||||
Incoming Value Transformations:
|
||||
```
|
||||
JS:tuya-in.js
|
||||
```
|
||||
|
||||
#### Valve percent
|
||||
Channel identifier:
|
||||
```
|
||||
valve_percent
|
||||
```
|
||||
|
||||
State:
|
||||
```
|
||||
tuya/zgw1/1a24fkfffe6b4e24/dsp/109/state
|
||||
```
|
||||
|
||||
Command:
|
||||
```
|
||||
tuya/zgw1/dps/command
|
||||
```
|
||||
|
||||
Outgoing Value Format:
|
||||
```
|
||||
{"dps": 109, "set": %s, "cid": "1a24fkfffe6b4e24"}
|
||||
```
|
||||
|
||||
### Transformations
|
||||
tuya-in.js:
|
||||
```
|
||||
(function(i) {
|
||||
return (i / 10)
|
||||
})(input)
|
||||
```
|
||||
|
||||
tuya-out.js:
|
||||
```
|
||||
(function(i) {
|
||||
return (i * 10)
|
||||
})(input)
|
||||
|
||||
```
|
||||
|
||||
### items/thermostat.items
|
||||
|
||||
```
|
||||
String Radiator_Mode "Mode" <radiator> { channel="mqtt:topic:home:zgw1dev1:mode" }
|
||||
Number Radiator_Setpoint "Temperature setpoint [%.1f °C]" <radiator> { channel="mqtt:topic:home:zgw1dev1:setpoint" }
|
||||
Number Radiator_Temperature "Current temperature [%.1f °C]" <temperature> { channel="mqtt:topic:home:zgw1dev1:temperature" }
|
||||
Number Radiator_Valve_Percent "Valve percent [%d %%]" { channel="mqtt:topic:home:zgw1dev1:valve_percent" }
|
||||
```
|
||||
|
||||
### sitemaps/home.sitemap
|
||||
|
||||
```
|
||||
Frame label="Heating" {
|
||||
Setpoint item=Radiator_Setpoint minValue=15 maxValue=30 step=0.5
|
||||
Selection item=Radiator_Mode mappings=[auto='Auto', temp_auto='Auto temp', manual='Manual', comfort='Comfort']
|
||||
Text item=Radiator_Setpoint
|
||||
Text item=Radiator_Temperature
|
||||
Text item=Radiator_Valve_Percent
|
||||
}
|
||||
|
||||
Switch tuya_livingroom_ledstrip_tv "LED Regal" <lightbulb> (<GROUPS>) ["Lighting"] {
|
||||
mqtt="<[broker:tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/state:state:default:.*],
|
||||
>[broker:tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/command/on:command:ON:true],
|
||||
>[broker:tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/command/off:command:OFF:false]"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### change color of lightbulb
|
||||
|
||||
|
||||
|
||||
### Simple on/off switch with power measurement capability
|
||||
|
||||
### Things channels (configured via web):
|
||||
|
||||
#### Power switch
|
||||
Channel identifier:
|
||||
```
|
||||
power
|
||||
```
|
||||
|
||||
# .items
|
||||
Group gTuyaLivingColor "Tuya color group" <lightbulb>
|
||||
Color tuya_livingroom_colorpicker "Stehlampe farbe" (LivingDining)
|
||||
|
||||
String tuya_livingroom_ledstrip_tv_color "Set color [%s]" (gTuyaLivingColor, LivingDining) {
|
||||
mqtt=">[broker:tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/color:command:*:default]"
|
||||
}
|
||||
|
||||
|
||||
|
||||
# .rules
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
|
||||
rule "Set HSB value of item RGBLed to RGB color value"
|
||||
when
|
||||
Item tuya_livingroom_colorpicker received command
|
||||
then
|
||||
var appName = "Colorpicker.livingroom"
|
||||
var color = receivedCommand.toString;
|
||||
|
||||
// get all colors and send it via mqtt if light ist enabled
|
||||
gTuyaLivingColor.members.forEach[ i |
|
||||
var name = i.name;
|
||||
var stateName = name.toString.split("_color").get(0);
|
||||
var stateItem = gTuyaLights.allMembers.filter [ conf | conf.name.contains(stateName.toString) ].head;
|
||||
|
||||
if(stateItem.state == ON){
|
||||
logInfo(appName, name + " change to color: " + color);
|
||||
i.sendCommand(color);
|
||||
Thread::sleep(400);
|
||||
}
|
||||
]
|
||||
end
|
||||
State:
|
||||
```
|
||||
tuya/tuya_device_1/state
|
||||
```
|
||||
Example output: {"4":"auto"}
|
||||
Possible values: auto/temp_auto/holiday/manual/comfort/eco/BOOST
|
||||
|
||||
Command:
|
||||
```
|
||||
tuya/tuya_device_1/command
|
||||
```
|
||||
|
||||
## Example items for OpenHAB 2.4 Bindings
|
||||
### simple switch on/off
|
||||
|
||||
With OpenHAB 2.X MQTT bindings you can add devices using a generic MQTT Thing via PaperUI or
|
||||
configuration files. For PaperUI simply at the generic MQTT Thing and set the state and
|
||||
command topics as follows:
|
||||
Custom On/Open Value:
|
||||
```
|
||||
ON
|
||||
```
|
||||
|
||||
tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/state
|
||||
|
||||
tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/command
|
||||
|
||||
Custom Off/Closed Value:
|
||||
```
|
||||
OFF
|
||||
```
|
||||
|
||||
If you prefer using configuration files vs PaperUI, it should look something like this:
|
||||
See also OpenHAB 2.X MQTT binding [documentation](https://www.openhab.org/v2.4/addons/bindings/mqtt.generic/)
|
||||
|
||||
#### Power consumption watts
|
||||
Channel identifier:
|
||||
```
|
||||
w
|
||||
```
|
||||
|
||||
Bridge mqtt:broker:myUnsecureBroker [ host="localhost", secure=false ]
|
||||
{
|
||||
|
||||
Thing mqtt:topic:myCustomMQTT {
|
||||
Channels:
|
||||
Type switch : tuya_kitchen_coffeemachine_mqtt_channel "Kitchen Coffee Machine MQTT Channel" [
|
||||
stateTopic="tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/state",
|
||||
commandTopic="tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/command",
|
||||
|
||||
// optional custom mqtt-payloads for ON and OFF
|
||||
on="{ \"dps\": 1, \"set\": true }",
|
||||
off="0"
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# *.item Example
|
||||
Switch tuya_kitchen_coffeemachine_mqtt "Kitchen Coffee Machine Switch" <socket> (gKitchen, gTuya) ["Switchable"] {
|
||||
channel="mqtt:topic:myUnsecureBroker:myCustomMQTT:tuya_kitchen_coffeemachine_mqtt_channel"
|
||||
}
|
||||
|
||||
State:
|
||||
```
|
||||
tuya/tuya_device_1/dps/19/state
|
||||
```
|
||||
|
||||
For one RGB bulb you would need a separate channel with the command topic set to
|
||||
`tuya/<tuyAPI-id>/<tuyAPI-key>/<tuyAPI-ip>/color` and link that to your color item.
|
||||
Incoming Value Transformations:
|
||||
JS:tuya-energy.js
|
||||
|
||||
#### Power consumption volts
|
||||
Channel identifier:
|
||||
```
|
||||
v
|
||||
```
|
||||
|
||||
Bridge mqtt:broker:myUnsecureBroker [ host="localhost", secure=false ]
|
||||
{
|
||||
Thing mqtt:topic:myCustomMQTT {
|
||||
Channels:
|
||||
Type colorHSB : livingroom_floorlamp_1_color "Livingroom floorlamp color MQTT Channel" [
|
||||
stateTopic="tuya/05200399bcddc2e02ec9/b58cf92e8bc5c899/192.168.178.49/state",
|
||||
commandTopic="tuya/05200399bcddc2e02ec9/b58cf92e8bc5c899/192.168.178.49/color"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# *.item Example
|
||||
Color tuya_livingroom_colorpicker "Floorlamp colorpicker" (gLivingroom){
|
||||
channel="mqtt:topic:myUnsecureBroker:myCustomMQTT:livingroom_floorlamp_1_color"
|
||||
}
|
||||
|
||||
State:
|
||||
```
|
||||
tuya/tuya_device_1/dps/20/state
|
||||
```
|
||||
|
||||
#### Basic UI sitemap
|
||||
Incoming Value Transformations:
|
||||
JS:tuya-energy.js
|
||||
|
||||
### transform/tuya-energy.js
|
||||
```
|
||||
(function(i) {
|
||||
return Math.ceil(i / 10)
|
||||
})(input)
|
||||
```
|
||||
|
||||
Switch item=tuya_kitchen_coffeemachine_mqtt
|
||||
### items/socket.items
|
||||
|
||||
# turn the color bulb off or on
|
||||
Switch item=tuya_livingroom_colorpicker label="RGB lamp [%s]"
|
||||
Switch Socket_Power "Socket" { channel="mqtt:topic:socket:power" }
|
||||
Number Socket_W "Power (W)" { channel="mqtt:topic:socket:w" }
|
||||
Number Socket_Vt "Power (V) [%s]" { channel="mqtt:topic:socket:v" }
|
||||
|
||||
# pick the color level to send to the color bulb via MQTT color Channel
|
||||
Slider item=tuya_livingroom_colorpicker label="RGB lamp level [%s]" minValue=0 maxValue=100 step=1
|
||||
### sitemaps/home.sitempa
|
||||
|
||||
# color picked and sent via MQTT Color channel
|
||||
Colorpicker item=tuya_livingroom_colorpicker label="RGB lamp color [%s]" icon="colorpicker" sendFrequency=30000
|
||||
|
||||
|
||||
```
|
||||
Switch item=Socket_Power
|
||||
Text item=Socket_W
|
||||
Text item=Socket_Vt
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "tuya-mqtt",
|
||||
"version": "3.0.4",
|
||||
"version": "3.1.4",
|
||||
"description": "Control Tuya devices locally via MQTT",
|
||||
"homepage": "https://github.com/TheAgentK/tuya-mqtt#readme",
|
||||
"homepage": "https://github.com/lehanspb/tuya-mqtt#readme",
|
||||
"main": "tuya-mqtt.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
@@ -19,11 +19,11 @@
|
||||
"json5": "^2.1.3",
|
||||
"mqtt": "^4.2.6",
|
||||
"supports-color": "^8.1.0",
|
||||
"tuyapi": "^6.1.4",
|
||||
"tuyapi": "^7.5.1",
|
||||
"mathjs": "8.1.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/TheAgentK/tuya-mqtt.git"
|
||||
"url": "git://github.com/lehanspb/tuya-mqtt.git"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +165,11 @@ const main = async() => {
|
||||
const dpsKey = splitTopic[topicLength-2]
|
||||
device.processDpsKeyCommand(message, dpsKey)
|
||||
break;
|
||||
case 6:
|
||||
const subDevDpsKey = splitTopic[topicLength-2]
|
||||
const cidName = splitTopic[topicLength-4]
|
||||
device.processDpsKeyWcidNameCommand(message, subDevDpsKey, cidName)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user