ESPHome  2024.4.0
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 };
64 
65 enum class TuyaInitState : uint8_t {
66  INIT_HEARTBEAT = 0x00,
68  INIT_CONF,
69  INIT_WIFI,
71  INIT_DONE,
72 };
73 
74 struct TuyaCommand {
76  std::vector<uint8_t> payload;
77 };
78 
79 class Tuya : public Component, public uart::UARTDevice {
80  public:
81  float get_setup_priority() const override { return setup_priority::LATE; }
82  void setup() override;
83  void loop() override;
84  void dump_config() override;
85  void register_listener(uint8_t datapoint_id, const std::function<void(TuyaDatapoint)> &func);
86  void set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value);
87  void set_boolean_datapoint_value(uint8_t datapoint_id, bool value);
88  void set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value);
89  void set_status_pin(InternalGPIOPin *status_pin) { this->status_pin_ = status_pin; }
90  void set_string_datapoint_value(uint8_t datapoint_id, const std::string &value);
91  void set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value);
92  void set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length);
93  void force_set_raw_datapoint_value(uint8_t datapoint_id, const std::vector<uint8_t> &value);
94  void force_set_boolean_datapoint_value(uint8_t datapoint_id, bool value);
95  void force_set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value);
96  void force_set_string_datapoint_value(uint8_t datapoint_id, const std::string &value);
97  void force_set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value);
98  void force_set_bitmask_datapoint_value(uint8_t datapoint_id, uint32_t value, uint8_t length);
99  TuyaInitState get_init_state();
100 #ifdef USE_TIME
101  void set_time_id(time::RealTimeClock *time_id) { this->time_id_ = time_id; }
102 #endif
103  void add_ignore_mcu_update_on_datapoints(uint8_t ignore_mcu_update_on_datapoints) {
104  this->ignore_mcu_update_on_datapoints_.push_back(ignore_mcu_update_on_datapoints);
105  }
106  void add_on_initialized_callback(std::function<void()> callback) {
107  this->initialized_callback_.add(std::move(callback));
108  }
109 
110  protected:
111  void handle_char_(uint8_t c);
112  void handle_datapoints_(const uint8_t *buffer, size_t len);
113  optional<TuyaDatapoint> get_datapoint_(uint8_t datapoint_id);
114  bool validate_message_();
115 
116  void handle_command_(uint8_t command, uint8_t version, const uint8_t *buffer, size_t len);
117  void send_raw_command_(TuyaCommand command);
118  void process_command_queue_();
119  void send_command_(const TuyaCommand &command);
120  void send_empty_command_(TuyaCommandType command);
121  void set_numeric_datapoint_value_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, uint32_t value,
122  uint8_t length, bool forced);
123  void set_string_datapoint_value_(uint8_t datapoint_id, const std::string &value, bool forced);
124  void set_raw_datapoint_value_(uint8_t datapoint_id, const std::vector<uint8_t> &value, bool forced);
125  void send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector<uint8_t> data);
126  void set_status_pin_();
127  void send_wifi_status_();
128  uint8_t get_wifi_status_code_();
129  uint8_t get_wifi_rssi_();
130 
131 #ifdef USE_TIME
132  void send_local_time_();
133  time::RealTimeClock *time_id_{nullptr};
134  bool time_sync_callback_registered_{false};
135 #endif
137  bool init_failed_{false};
138  int init_retries_{0};
139  uint8_t protocol_version_ = -1;
140  InternalGPIOPin *status_pin_{nullptr};
141  int status_pin_reported_ = -1;
142  int reset_pin_reported_ = -1;
143  uint32_t last_command_timestamp_ = 0;
144  uint32_t last_rx_char_timestamp_ = 0;
145  std::string product_ = "";
146  std::vector<TuyaDatapointListener> listeners_;
147  std::vector<TuyaDatapoint> datapoints_;
148  std::vector<uint8_t> rx_message_;
149  std::vector<uint8_t> ignore_mcu_update_on_datapoints_{};
150  std::vector<TuyaCommand> command_queue_;
151  optional<TuyaCommandType> expected_response_{};
152  uint8_t wifi_status_ = -1;
153  CallbackManager<void()> initialized_callback_{};
154 };
155 
156 } // namespace tuya
157 } // namespace esphome
void setup()
void loop()
TuyaDatapointType type
Definition: tuya.h:30
TuyaCommandType
Definition: tuya.h:48
float get_setup_priority() const override
Definition: tuya.h:81
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:101
TuyaDatapointType
Definition: tuya.h:19
std::vector< TuyaDatapointListener > listeners_
Definition: tuya.h:146
void add_on_initialized_callback(std::function< void()> callback)
Definition: tuya.h:106
std::vector< TuyaDatapoint > datapoints_
Definition: tuya.h:147
std::vector< uint8_t > rx_message_
Definition: tuya.h:148
TuyaCommandType cmd
Definition: tuya.h:75
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:76
void set_status_pin(InternalGPIOPin *status_pin)
Definition: tuya.h:89
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:150
TuyaInitState
Definition: tuya.h:65
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:103