ESPHome  2024.6.1
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,
56  DATAPOINT_REPORT = 0x07,
57  DATAPOINT_QUERY = 0x08,
58  WIFI_TEST = 0x0E,
59  LOCAL_TIME_QUERY = 0x1C,
60  WIFI_RSSI = 0x24,
61  VACUUM_MAP_UPLOAD = 0x28,
62  GET_NETWORK_STATUS = 0x2B,
63  EXTENDED_SERVICES = 0x34,
64 };
65 
66 enum class TuyaExtendedServicesCommandType : uint8_t {
67  RESET_NOTIFICATION = 0x04,
68  MODULE_RESET = 0x05,
69  UPDATE_IN_PROGRESS = 0x0A,
70 };
71 
72 enum class TuyaInitState : uint8_t {
73  INIT_HEARTBEAT = 0x00,
75  INIT_CONF,
76  INIT_WIFI,
78  INIT_DONE,
79 };
80 
81 struct TuyaCommand {
83  std::vector<uint8_t> payload;
84 };
85 
86 class Tuya : public Component, public uart::UARTDevice {
87  public:
88  float get_setup_priority() const override { return setup_priority::LATE; }
89  void setup() override;
90  void loop() override;
91  void dump_config() override;
92  void register_listener(uint8_t datapoint_id, const std::function<void(TuyaDatapoint)> &func);
93  void set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value);
94  void set_boolean_datapoint_value(uint8_t datapoint_id, bool value);
95  void set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value);
96  void set_status_pin(InternalGPIOPin *status_pin) { this->status_pin_ = status_pin; }
97  void set_string_datapoint_value(uint8_t datapoint_id, const std::string &value);
98  void set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value);
99  void set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length);
100  void force_set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value);
101  void force_set_boolean_datapoint_value(uint8_t datapoint_id, bool value);
102  void force_set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value);
103  void force_set_string_datapoint_value(uint8_t datapoint_id, const std::string &value);
104  void force_set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value);
105  void force_set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length);
106  TuyaInitState get_init_state();
107 #ifdef USE_TIME
108  void set_time_id(time::RealTimeClock *time_id) { this->time_id_ = time_id; }
109 #endif
110  void add_ignore_mcu_update_on_datapoints(uint8_t ignore_mcu_update_on_datapoints) {
111  this->ignore_mcu_update_on_datapoints_.push_back(ignore_mcu_update_on_datapoints);
112  }
113  void add_on_initialized_callback(std::function<void()> callback) {
114  this->initialized_callback_.add(std::move(callback));
115  }
116 
117  protected:
118  void handle_char_(uint8_t c);
119  void handle_datapoints_(const uint8_t *buffer, size_t len);
120  optional<TuyaDatapoint> get_datapoint_(uint8_t datapoint_id);
121  bool validate_message_();
122 
123  void handle_command_(uint8_t command, uint8_t version, const uint8_t *buffer, size_t len);
124  void send_raw_command_(TuyaCommand command);
125  void process_command_queue_();
126  void send_command_(const TuyaCommand &command);
127  void send_empty_command_(TuyaCommandType command);
128  void set_numeric_datapoint_value_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, uint32_t value,
129  uint8_t length, bool forced);
130  void set_string_datapoint_value_(uint8_t datapoint_id, const std::string &value, bool forced);
131  void set_raw_datapoint_value_(uint8_t datapoint_id, const std::vector<uint8_t> &value, bool forced);
132  void send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector<uint8_t> data);
133  void set_status_pin_();
134  void send_wifi_status_();
135  uint8_t get_wifi_status_code_();
136  uint8_t get_wifi_rssi_();
137 
138 #ifdef USE_TIME
139  void send_local_time_();
140  time::RealTimeClock *time_id_{nullptr};
141  bool time_sync_callback_registered_{false};
142 #endif
144  bool init_failed_{false};
145  int init_retries_{0};
146  uint8_t protocol_version_ = -1;
147  InternalGPIOPin *status_pin_{nullptr};
148  int status_pin_reported_ = -1;
149  int reset_pin_reported_ = -1;
150  uint32_t last_command_timestamp_ = 0;
151  uint32_t last_rx_char_timestamp_ = 0;
152  std::string product_ = "";
153  std::vector<TuyaDatapointListener> listeners_;
154  std::vector<TuyaDatapoint> datapoints_;
155  std::vector<uint8_t> rx_message_;
156  std::vector<uint8_t> ignore_mcu_update_on_datapoints_{};
157  std::vector<TuyaCommand> command_queue_;
158  optional<TuyaCommandType> expected_response_{};
159  uint8_t wifi_status_ = -1;
160  CallbackManager<void()> initialized_callback_{};
161 };
162 
163 } // namespace tuya
164 } // namespace esphome
void setup()
TuyaExtendedServicesCommandType
Definition: tuya.h:66
void loop()
TuyaDatapointType type
Definition: tuya.h:30
TuyaCommandType
Definition: tuya.h:48
float get_setup_priority() const override
Definition: tuya.h:88
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:108
TuyaDatapointType
Definition: tuya.h:19
std::vector< TuyaDatapointListener > listeners_
Definition: tuya.h:153
void add_on_initialized_callback(std::function< void()> callback)
Definition: tuya.h:113
std::vector< TuyaDatapoint > datapoints_
Definition: tuya.h:154
std::vector< uint8_t > rx_message_
Definition: tuya.h:155
TuyaCommandType cmd
Definition: tuya.h:82
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:83
void set_status_pin(InternalGPIOPin *status_pin)
Definition: tuya.h:96
std::string size_t len
Definition: helpers.h:292
uint16_t length
Definition: tt21100.cpp:12
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
std::vector< TuyaCommand > command_queue_
Definition: tuya.h:157
TuyaInitState
Definition: tuya.h:72
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:110