ESPHome  2024.3.1
mqtt_fan.cpp
Go to the documentation of this file.
1 #include "mqtt_fan.h"
2 #include "esphome/core/log.h"
3 
4 #include "mqtt_const.h"
5 
6 #ifdef USE_MQTT
7 #ifdef USE_FAN
8 
9 namespace esphome {
10 namespace mqtt {
11 
12 static const char *const TAG = "mqtt.fan";
13 
14 using namespace esphome::fan;
15 
17 
18 Fan *MQTTFanComponent::get_state() const { return this->state_; }
19 std::string MQTTFanComponent::component_type() const { return "fan"; }
20 const EntityBase *MQTTFanComponent::get_entity() const { return this->state_; }
21 
23  this->subscribe(this->get_command_topic_(), [this](const std::string &topic, const std::string &payload) {
24  auto val = parse_on_off(payload.c_str());
25  switch (val) {
26  case PARSE_ON:
27  ESP_LOGD(TAG, "'%s' Turning Fan ON.", this->friendly_name().c_str());
28  this->state_->turn_on().perform();
29  break;
30  case PARSE_OFF:
31  ESP_LOGD(TAG, "'%s' Turning Fan OFF.", this->friendly_name().c_str());
32  this->state_->turn_off().perform();
33  break;
34  case PARSE_TOGGLE:
35  ESP_LOGD(TAG, "'%s' Toggling Fan.", this->friendly_name().c_str());
36  this->state_->toggle().perform();
37  break;
38  case PARSE_NONE:
39  default:
40  ESP_LOGW(TAG, "Unknown state payload %s", payload.c_str());
41  this->status_momentary_warning("state", 5000);
42  break;
43  }
44  });
45 
46  if (this->state_->get_traits().supports_oscillation()) {
47  this->subscribe(this->get_oscillation_command_topic(),
48  [this](const std::string &topic, const std::string &payload) {
49  auto val = parse_on_off(payload.c_str(), "oscillate_on", "oscillate_off");
50  switch (val) {
51  case PARSE_ON:
52  ESP_LOGD(TAG, "'%s': Setting oscillating ON", this->friendly_name().c_str());
53  this->state_->make_call().set_oscillating(true).perform();
54  break;
55  case PARSE_OFF:
56  ESP_LOGD(TAG, "'%s': Setting oscillating OFF", this->friendly_name().c_str());
57  this->state_->make_call().set_oscillating(false).perform();
58  break;
59  case PARSE_TOGGLE:
61  break;
62  case PARSE_NONE:
63  ESP_LOGW(TAG, "Unknown Oscillation Payload %s", payload.c_str());
64  this->status_momentary_warning("oscillation", 5000);
65  break;
66  }
67  });
68  }
69 
70  if (this->state_->get_traits().supports_speed()) {
71  this->subscribe(this->get_speed_level_command_topic(),
72  [this](const std::string &topic, const std::string &payload) {
73  optional<int> speed_level_opt = parse_number<int>(payload);
74  if (speed_level_opt.has_value()) {
75  const int speed_level = speed_level_opt.value();
76  if (speed_level >= 0 && speed_level <= this->state_->get_traits().supported_speed_count()) {
77  ESP_LOGD(TAG, "New speed level %d", speed_level);
78  this->state_->make_call().set_speed(speed_level).perform();
79  } else {
80  ESP_LOGW(TAG, "Invalid speed level %d", speed_level);
81  this->status_momentary_warning("speed", 5000);
82  }
83  } else {
84  ESP_LOGW(TAG, "Invalid speed level %s (int expected)", payload.c_str());
85  this->status_momentary_warning("speed", 5000);
86  }
87  });
88  }
89 
90  auto f = std::bind(&MQTTFanComponent::publish_state, this);
91  this->state_->add_on_state_callback([this, f]() { this->defer("send", f); });
92 }
93 
95  ESP_LOGCONFIG(TAG, "MQTT Fan '%s': ", this->state_->get_name().c_str());
96  LOG_MQTT_COMPONENT(true, true);
97  if (this->state_->get_traits().supports_oscillation()) {
98  ESP_LOGCONFIG(TAG, " Oscillation State Topic: '%s'", this->get_oscillation_state_topic().c_str());
99  ESP_LOGCONFIG(TAG, " Oscillation Command Topic: '%s'", this->get_oscillation_command_topic().c_str());
100  }
101  if (this->state_->get_traits().supports_speed()) {
102  ESP_LOGCONFIG(TAG, " Speed Level State Topic: '%s'", this->get_speed_level_state_topic().c_str());
103  ESP_LOGCONFIG(TAG, " Speed Level Command Topic: '%s'", this->get_speed_level_command_topic().c_str());
104  }
105 }
106 
108 
110  if (this->state_->get_traits().supports_oscillation()) {
111  root[MQTT_OSCILLATION_COMMAND_TOPIC] = this->get_oscillation_command_topic();
112  root[MQTT_OSCILLATION_STATE_TOPIC] = this->get_oscillation_state_topic();
113  }
114  if (this->state_->get_traits().supports_speed()) {
115  root[MQTT_PERCENTAGE_COMMAND_TOPIC] = this->get_speed_level_command_topic();
116  root[MQTT_PERCENTAGE_STATE_TOPIC] = this->get_speed_level_state_topic();
118  }
119 }
121  const char *state_s = this->state_->state ? "ON" : "OFF";
122  ESP_LOGD(TAG, "'%s' Sending state %s.", this->state_->get_name().c_str(), state_s);
123  this->publish(this->get_state_topic_(), state_s);
124  bool failed = false;
125  if (this->state_->get_traits().supports_oscillation()) {
126  bool success = this->publish(this->get_oscillation_state_topic(),
127  this->state_->oscillating ? "oscillate_on" : "oscillate_off");
128  failed = failed || !success;
129  }
130  auto traits = this->state_->get_traits();
131  if (traits.supports_speed()) {
132  std::string payload = to_string(this->state_->speed);
133  bool success = this->publish(this->get_speed_level_state_topic(), payload);
134  failed = failed || !success;
135  }
136  return !failed;
137 }
138 
139 } // namespace mqtt
140 } // namespace esphome
141 
142 #endif
143 #endif // USE_MQTT
value_type const & value() const
Definition: optional.h:89
bool state
The current on/off state of the fan.
Definition: fan.h:110
bool oscillating
The current oscillation state of the fan.
Definition: fan.h:112
MQTTFanComponent(fan::Fan *state)
Definition: mqtt_fan.cpp:16
void setup() override
Setup the fan subscriptions and discovery.
Definition: mqtt_fan.cpp:22
const EntityBase * get_entity() const override
Definition: mqtt_fan.cpp:20
void status_momentary_warning(const std::string &name, uint32_t length=5000)
Definition: component.cpp:173
virtual FanTraits get_traits()=0
void defer(const std::string &name, std::function< void()> &&f)
Defer a callback to the next loop() call.
Definition: component.cpp:125
fan::Fan * get_state() const
Definition: mqtt_fan.cpp:18
mopeka_std_values val[4]
constexpr const char *const MQTT_OSCILLATION_STATE_TOPIC
Definition: mqtt_const.h:119
bool has_value() const
Definition: optional.h:87
bool supports_oscillation() const
Return if this fan supports oscillation.
Definition: fan_traits.h:16
bool publish(const std::string &topic, const std::string &payload)
Send a MQTT message.
ParseOnOffState parse_on_off(const char *str, const char *on, const char *off)
Parse a string that contains either on, off or toggle.
Definition: helpers.cpp:397
int supported_speed_count() const
Return how many speed levels the fan has.
Definition: fan_traits.h:24
void add_on_state_callback(std::function< void()> &&callback)
Register a callback that will be called each time the state changes.
Definition: fan.cpp:116
std::string component_type() const override
&#39;fan&#39; component type for discovery.
Definition: mqtt_fan.cpp:19
state state state void send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) override
Definition: mqtt_fan.cpp:109
FanCall turn_off()
Definition: fan.cpp:112
void subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos=0)
Subscribe to a MQTT topic.
FanCall & set_speed(int speed)
Definition: fan.h:59
FanCall toggle()
Definition: fan.cpp:113
int speed
The current fan speed level.
Definition: fan.h:114
Simple Helper struct used for Home Assistant MQTT send_discovery().
constexpr const char *const MQTT_OSCILLATION_COMMAND_TOPIC
Definition: mqtt_const.h:117
constexpr const char *const MQTT_PERCENTAGE_COMMAND_TOPIC
Definition: mqtt_const.h:121
FanCall & set_oscillating(bool oscillating)
Definition: fan.h:50
constexpr const char *const MQTT_PERCENTAGE_STATE_TOPIC
Definition: mqtt_const.h:123
constexpr const char *const MQTT_SPEED_RANGE_MAX
Definition: mqtt_const.h:196
bool send_initial_state() override
Send the full current state to MQTT.
Definition: mqtt_fan.cpp:107
constexpr const char * c_str() const
Definition: string_ref.h:68
std::string to_string(int value)
Definition: helpers.cpp:82
FanCall make_call()
Definition: fan.cpp:114
virtual std::string friendly_name() const
Get the friendly name of this MQTT component.
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::string get_state_topic_() const
Get the MQTT topic that new states will be shared to.
std::string get_command_topic_() const
Get the MQTT topic for listening to commands.
const StringRef & get_name() const
Definition: entity_base.cpp:10
bool state
Definition: fan.h:34
bool supports_speed() const
Return if this fan supports speed modes.
Definition: fan_traits.h:20
FanCall turn_on()
Definition: fan.cpp:111