ESPHome  2024.7.2
tuya.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <cinttypes>
4 #include <vector>
5 
7 #include "esphome/core/defines.h"
8 #include "esphome/core/helpers.h"
10 
11 #ifdef USE_TIME
13 #include "esphome/core/time.h"
14 #endif
15 
16 namespace esphome {
17 namespace tuya {
18 
19 enum class TuyaDatapointType : uint8_t {
20  RAW = 0x00, // variable length
21  BOOLEAN = 0x01, // 1 byte (0/1)
22  INTEGER = 0x02, // 4 byte
23  STRING = 0x03, // variable length
24  ENUM = 0x04, // 1 byte
25  BITMASK = 0x05, // 1/2/4 bytes
26 };
27 
28 struct TuyaDatapoint {
29  uint8_t id;
31  size_t len;
32  union {
33  bool value_bool;
34  int value_int;
35  uint32_t value_uint;
36  uint8_t value_enum;
37  uint32_t value_bitmask;
38  };
39  std::string value_string;
40  std::vector<uint8_t> value_raw;
41 };
42 
44  uint8_t datapoint_id;
45  std::function<void(TuyaDatapoint)> on_datapoint;
46 };
47 
48 enum class TuyaCommandType : uint8_t {
49  HEARTBEAT = 0x00,
50  PRODUCT_QUERY = 0x01,
51  CONF_QUERY = 0x02,
52  WIFI_STATE = 0x03,
53  WIFI_RESET = 0x04,
54  WIFI_SELECT = 0x05,
55  DATAPOINT_DELIVER = 0x06,
57  DATAPOINT_QUERY = 0x08,
58  WIFI_TEST = 0x0E,
59  LOCAL_TIME_QUERY = 0x1C,
60  DATAPOINT_REPORT_SYNC = 0x22,
61  DATAPOINT_REPORT_ACK = 0x23,
62  WIFI_RSSI = 0x24,
63  VACUUM_MAP_UPLOAD = 0x28,
64  GET_NETWORK_STATUS = 0x2B,
65  EXTENDED_SERVICES = 0x34,
66 };
67 
68 enum class TuyaExtendedServicesCommandType : uint8_t {
69  RESET_NOTIFICATION = 0x04,
70  MODULE_RESET = 0x05,
71  UPDATE_IN_PROGRESS = 0x0A,
72 };
73 
74 enum class TuyaInitState : uint8_t {
75  INIT_HEARTBEAT = 0x00,
77  INIT_CONF,
78  INIT_WIFI,
80  INIT_DONE,
81 };
82 
83 struct TuyaCommand {
85  std::vector<uint8_t> payload;
86 };
87 
88 class Tuya : public Component, public uart::UARTDevice {
89  public:
90  float get_setup_priority() const override { return setup_priority::LATE; }
91  void setup() override;
92  void loop() override;
93  void dump_config() override;
94  void register_listener(uint8_t datapoint_id, const std::function<void(TuyaDatapoint)> &func);
95  void set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value);
96  void set_boolean_datapoint_value(uint8_t datapoint_id, bool value);
97  void set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value);
98  void set_status_pin(InternalGPIOPin *status_pin) { this->status_pin_ = status_pin; }
99  void set_string_datapoint_value(uint8_t datapoint_id, const std::string &value);
100  void set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value);
101  void set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length);
102  void force_set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value);
103  void force_set_boolean_datapoint_value(uint8_t datapoint_id, bool value);
104  void force_set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value);
105  void force_set_string_datapoint_value(uint8_t datapoint_id, const std::string &value);
106  void force_set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value);
107  void force_set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length);
108  TuyaInitState get_init_state();
109 #ifdef USE_TIME
110  void set_time_id(time::RealTimeClock *time_id) { this->time_id_ = time_id; }
111 #endif
112  void add_ignore_mcu_update_on_datapoints(uint8_t ignore_mcu_update_on_datapoints) {
113  this->ignore_mcu_update_on_datapoints_.push_back(ignore_mcu_update_on_datapoints);
114  }
115  void add_on_initialized_callback(std::function<void()> callback) {
116  this->initialized_callback_.add(std::move(callback));
117  }
118 
119  protected:
120  void handle_char_(uint8_t c);
121  void handle_datapoints_(const uint8_t *buffer, size_t len);
122  optional<TuyaDatapoint> get_datapoint_(uint8_t datapoint_id);
123  bool validate_message_();
124 
125  void handle_command_(uint8_t command, uint8_t version, const uint8_t *buffer, size_t len);
126  void send_raw_command_(TuyaCommand command);
127  void process_command_queue_();
128  void send_command_(const TuyaCommand &command);
129  void send_empty_command_(TuyaCommandType command);
130  void set_numeric_datapoint_value_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, uint32_t value,
131  uint8_t length, bool forced);
132  void set_string_datapoint_value_(uint8_t datapoint_id, const std::string &value, bool forced);
133  void set_raw_datapoint_value_(uint8_t datapoint_id, const std::vector<uint8_t> &value, bool forced);
134  void send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector<uint8_t> data);
135  void set_status_pin_();
136  void send_wifi_status_();
137  uint8_t get_wifi_status_code_();
138  uint8_t get_wifi_rssi_();
139 
140 #ifdef USE_TIME
141  void send_local_time_();
142  time::RealTimeClock *time_id_{nullptr};
143  bool time_sync_callback_registered_{false};
144 #endif
146  bool init_failed_{false};
147  int init_retries_{0};
148  uint8_t protocol_version_ = -1;
149  InternalGPIOPin *status_pin_{nullptr};
150  int status_pin_reported_ = -1;
151  int reset_pin_reported_ = -1;
152  uint32_t last_command_timestamp_ = 0;
153  uint32_t last_rx_char_timestamp_ = 0;
154  std::string product_ = "";
155  std::vector<TuyaDatapointListener> listeners_;
156  std::vector<TuyaDatapoint> datapoints_;
157  std::vector<uint8_t> rx_message_;
158  std::vector<uint8_t> ignore_mcu_update_on_datapoints_{};
159  std::vector<TuyaCommand> command_queue_;
160  optional<TuyaCommandType> expected_response_{};
161  uint8_t wifi_status_ = -1;
162  CallbackManager<void()> initialized_callback_{};
163 };
164 
165 } // namespace tuya
166 } // namespace esphome
void setup()
TuyaExtendedServicesCommandType
Definition: tuya.h:68
void loop()
TuyaDatapointType type
Definition: tuya.h:30
TuyaCommandType
Definition: tuya.h:48
float get_setup_priority() const override
Definition: tuya.h:90
The RealTimeClock class exposes common timekeeping functions via the device&#39;s local real-time clock...
const float LATE
For components that should be initialized at the very end of the setup process.
Definition: component.cpp:28
void set_time_id(time::RealTimeClock *time_id)
Definition: tuya.h:110
TuyaDatapointType
Definition: tuya.h:19
std::vector< TuyaDatapointListener > listeners_
Definition: tuya.h:155
void add_on_initialized_callback(std::function< void()> callback)
Definition: tuya.h:115
std::vector< TuyaDatapoint > datapoints_
Definition: tuya.h:156
std::vector< uint8_t > rx_message_
Definition: tuya.h:157
TuyaCommandType cmd
Definition: tuya.h:84
std::string value_string
Definition: tuya.h:39
std::function< void(TuyaDatapoint)> on_datapoint
Definition: tuya.h:45
std::vector< uint8_t > payload
Definition: tuya.h:85
void set_status_pin(InternalGPIOPin *status_pin)
Definition: tuya.h:98
std::string size_t len
Definition: helpers.h:292
uint16_t length
Definition: tt21100.cpp:12
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
std::vector< TuyaCommand > command_queue_
Definition: tuya.h:159
TuyaInitState
Definition: tuya.h:74
std::vector< uint8_t > value_raw
Definition: tuya.h:40
void add_ignore_mcu_update_on_datapoints(uint8_t ignore_mcu_update_on_datapoints)
Definition: tuya.h:112