Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select basic implementation #55

Merged
merged 5 commits into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
"istream": "cpp",
"sstream": "cpp",
"optional": "cpp",
"queue": "cpp"
"queue": "cpp",
"iosfwd": "cpp",
"xlocbuf": "cpp",
"atomic": "cpp"
},
"files.trimTrailingWhitespace": true,
"files.exclude": {
Expand Down
17 changes: 12 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
Please, don't change. In case you need to make corrections or changes change
source documentation in ./doc folder or script.

.. Generated from see_also.rst

.. Generated from esphome-docs/climate/haier.rst

Haier Climate
Expand Down Expand Up @@ -567,19 +569,24 @@ flash_4M.bin**

After this, you can flash firmware using ESPHome tools (dashboard,
website, esphome command, etc)
.. Generated from additional_information.rst

Additional information
======================
See Also
========

- `FAQ <./docs/faq.rst>`_
- `HaierProtocol <https://github.com/paveldn/HaierProtocol>`_
- `Haier smart modules <./docs/haier_modules.rst>`_
- `Haier protocol overview <./docs/protocol_overview.rst>`_
- `Example of climate configuration for smartair2 protocol <./docs/smartair2_example.rst>`_
- `Example of climate configuration for hOn protocol <./docs/hon_example.rst>`_
- `Esptool.py Documentation <https://docs.espressif.com/projects/esptool/en/latest/esp32/>`_
- `Sniffing serial communication <./docs/sniffing_serial_communication.rst>`_
- `ESPHome Haier Climate <https://esphome.io/components/climate/haier.html>`_
- `ESPHome Haier Climate Sensors <https://esphome.io/components/sensor/haier.html>`_
- `ESPHome Haier Climate Binary Sensors <https://esphome.io/components/binary_sensor/haier.html>`_
- `Esptool.py Documentation <https://docs.espressif.com/projects/esptool/en/latest/esp32/>`_
- `Sniffing serial communication <./docs/sniffing_serial_communication.rst>`_
- `ESPHome Haier Climate Text Sensors <https://esphome.io/components/text_sensor/haier.html>`_
- `ESPHome Haier Climate Buttons <https://esphome.io/components/button/haier.html>`_
- `ESPHome Haier Climate Switches <https://esphome.io/components/switch/haier.html>`_
- `Climate Component <https://esphome.io/components/climate/>`_
- `API Reference <https://esphome.io/api/haier__base_8h.html>`_
- `Sensor Filters <https://esphome.io/components/sensor/#sensor-filters>`_
20 changes: 20 additions & 0 deletions components/haier/hon_climate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include "esphome/core/helpers.h"
#include "hon_climate.h"
#include "hon_packet.h"
#ifdef USE_SELECT
#include "select/vertical_airflow.h"
#include "select/horizontal_airflow.h"
#endif

using namespace esphome::climate;
using namespace esphome::uart;
Expand Down Expand Up @@ -806,6 +810,22 @@ void HonClimate::set_quiet_mode_switch(switch_::Switch *sw) {
}
#endif // USE_SWITCH

#ifdef USE_SELECT
void HonClimate::set_vertical_airflow_select(select::Select *sel) {
// this->vertical_airflow_select_ = sel;
// if (this->current_vertical_swing_.has_value() && (this->vertical_airflow_select_ != nullptr)) {
// this->vertical_airflow_select_->publish_state(VerticalAirflowSelect::vertical_airflow_to_string(this->current_vertical_swing_.value()));
// }
}

void HonClimate::set_horizontal_airflow_select(select::Select *sel) {
// this->horizontal_airflow_select_ = sel;
// if (this->horizontal_airflow_select_ != nullptr) {
// this->horizontal_airflow_select_->publish_state((uint8_t) this->settings_.last_horizontal_swing);
// }
}
#endif // USE_SELECT

haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) {
size_t expected_size =
2 + this->status_message_header_size_ + this->real_control_packet_size_ + this->real_sensors_packet_size_;
Expand Down
12 changes: 12 additions & 0 deletions components/haier/hon_climate.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#ifdef USE_SWITCH
#include "esphome/components/switch/switch.h"
#endif
#ifdef USE_SELECT
#include "esphome/components/select/select.h"
#endif
#include "esphome/core/automation.h"
#include "haier_base.h"
#include "hon_packet.h"
Expand Down Expand Up @@ -100,6 +103,15 @@ class HonClimate : public HaierClimateBase {
protected:
switch_::Switch *beeper_switch_{nullptr};
switch_::Switch *quiet_mode_switch_{nullptr};
#endif
#ifdef USE_SELECT
public:
void set_vertical_airflow_select(select::Select *sel);
void set_horizontal_airflow_select(select::Select *sel);

protected:
select::Select *vertical_airflow_select_{nullptr};
select::Select *horizontal_airflow_select_{nullptr};
#endif
public:
HonClimate();
Expand Down
85 changes: 85 additions & 0 deletions components/haier/select/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import select
from esphome.const import (
CONF_OPTIONS,
ENTITY_CATEGORY_CONFIG,
)
from ..climate import (
CONF_HAIER_ID,
HonClimate,
haier_ns,
hon_protocol_ns,
CONF_VERTICAL_AIRFLOW,
CONF_HORIZONTAL_AIRFLOW,
)

CODEOWNERS = ["@paveldn"]
VerticalAirflowSelect = haier_ns.class_("VerticalAirflowSelect", select.Select)
HorizontalAirflowSelect = haier_ns.class_("HorizontalAirflowSelect", select.Select)

VerticalSwingMode = hon_protocol_ns.enum("VerticalSwingMode", True)
HorizontalSwingMode = hon_protocol_ns.enum("HorizontalSwingMode", True)

# Additional icons
ICON_ARROW_HORIZONTAL = "mdi:arrow-expand-horizontal"
ICON_ARROW_VERTICAL = "mdi:arrow-expand-vertical"

AIRFLOW_VERTICAL_DIRECTION_OPTIONS = {
"Auto": VerticalSwingMode.AUTO,
"Health Up": VerticalSwingMode.HEALTH_UP,
"Max Up": VerticalSwingMode.MAX_UP,
"Up": VerticalSwingMode.UP,
"Center": VerticalSwingMode.CENTER,
"Down": VerticalSwingMode.DOWN,
"Max Down": VerticalSwingMode.MAX_DOWN,
"Health Down": VerticalSwingMode.HEALTH_DOWN,
}

AIRFLOW_HORIZONTAL_DIRECTION_OPTIONS = {
"Auto": HorizontalSwingMode.AUTO,
"Max Left": HorizontalSwingMode.MAX_LEFT,
"Left": HorizontalSwingMode.LEFT,
"Center": HorizontalSwingMode.CENTER,
"Right": HorizontalSwingMode.RIGHT,
"Max Right": HorizontalSwingMode.MAX_RIGHT,
}

#def check_airflow_map(value, options_map):
# cv.check_not_templatable(value)
# option_key = cv.All(cv.string_strict)
# option_value =
# if value not in AIRFLOW_VERTICAL_DIRECTION_OPTIONS:
# raise cv.Invalid(f"Invalid airflow value {value}, must be one of: {', '.join(AIRFLOW_VERTICAL_DIRECTION_OPTIONS)}")
# return value

CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_HAIER_ID): cv.use_id(HonClimate),
cv.Optional(CONF_VERTICAL_AIRFLOW): select.select_schema(
VerticalAirflowSelect,
icon=ICON_ARROW_VERTICAL,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_HORIZONTAL_AIRFLOW): select.select_schema(
HorizontalAirflowSelect,
icon=ICON_ARROW_HORIZONTAL,
entity_category=ENTITY_CATEGORY_CONFIG,
),
}
)

async def to_code(config):
full_id, parent = await cg.get_variable_with_full_id(config[CONF_HAIER_ID])

if conf := config.get(CONF_VERTICAL_AIRFLOW):
sel_var = await select.new_select(conf, options=list(AIRFLOW_VERTICAL_DIRECTION_OPTIONS.keys()))
await cg.register_parented(sel_var, parent)
cg.add(getattr(parent, f"set_{CONF_VERTICAL_AIRFLOW}_select")(sel_var))

if conf := config.get(CONF_HORIZONTAL_AIRFLOW):
sel_var = await select.new_select(conf, options=list(AIRFLOW_HORIZONTAL_DIRECTION_OPTIONS.keys()))
await cg.register_parented(sel_var, parent)
cg.add(getattr(parent, f"set_{CONF_HORIZONTAL_AIRFLOW}_select")(sel_var))


33 changes: 33 additions & 0 deletions components/haier/select/horizontal_airflow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "horizontal_airflow.h"
#include <protocol/haier_protocol.h>

namespace esphome {
namespace haier {

void HorizontalAirflowSelect::control(const std::string &value) {
hon_protocol::HorizontalSwingMode state;
if (value == "Auto") {
state = hon_protocol::HorizontalSwingMode::AUTO;
} else if (value == "Max Left") {
state = hon_protocol::HorizontalSwingMode::MAX_LEFT;
} else if (value == "Left") {
state = hon_protocol::HorizontalSwingMode::LEFT;
} else if (value == "Center") {
state = hon_protocol::HorizontalSwingMode::CENTER;
} else if (value == "Right") {
state = hon_protocol::HorizontalSwingMode::RIGHT;
} else if (value == "Max Right") {
state = hon_protocol::HorizontalSwingMode::MAX_RIGHT;
} else {
ESP_LOGE("haier", "Invalid horizontal airflow mode: %s", value.c_str());
return;
}
const esphome::optional<hon_protocol::HorizontalSwingMode> current_state = this->parent_->get_horizontal_airflow();
if (!current_state.has_value() || (current_state.value() != state)) {
this->parent_->set_horizontal_airflow(state);
}
this->publish_state(value);
}

} // namespace haier
} // namespace esphome
18 changes: 18 additions & 0 deletions components/haier/select/horizontal_airflow.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include "esphome/components/select/select.h"
#include "../hon_climate.h"

namespace esphome {
namespace haier {

class HorizontalAirflowSelect : public select::Select, public Parented<HonClimate> {
public:
HorizontalAirflowSelect() = default;

protected:
void control(const std::string &value) override;
};

} // namespace haier
} // namespace esphome
37 changes: 37 additions & 0 deletions components/haier/select/vertical_airflow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "vertical_airflow.h"
#include <protocol/haier_protocol.h>

namespace esphome {
namespace haier {

void VerticalAirflowSelect::control(const std::string &value) {
hon_protocol::VerticalSwingMode state;
if (value == "Auto") {
state = hon_protocol::VerticalSwingMode::AUTO;
} else if (value == "Health Up") {
state = hon_protocol::VerticalSwingMode::HEALTH_UP;
} else if (value == "Max Up") {
state = hon_protocol::VerticalSwingMode::MAX_UP;
} else if (value == "Up") {
state = hon_protocol::VerticalSwingMode::UP;
} else if (value == "Center") {
state = hon_protocol::VerticalSwingMode::CENTER;
} else if (value == "Down") {
state = hon_protocol::VerticalSwingMode::DOWN;
} else if (value == "Max Down") {
state = hon_protocol::VerticalSwingMode::MAX_DOWN;
} else if (value == "Health Down") {
state = hon_protocol::VerticalSwingMode::HEALTH_DOWN;
} else {
ESP_LOGE("haier", "Invalid vertical airflow mode: %s", value.c_str());
return;
}
const esphome::optional<hon_protocol::VerticalSwingMode> current_state = this->parent_->get_vertical_airflow();
if (!current_state.has_value() || (current_state.value() != state)) {
this->parent_->set_vertical_airflow(state);
}
this->publish_state(value);
}

} // namespace haier
} // namespace esphome
18 changes: 18 additions & 0 deletions components/haier/select/vertical_airflow.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include "esphome/components/select/select.h"
#include "../hon_climate.h"

namespace esphome {
namespace haier {

class VerticalAirflowSelect : public select::Select, public Parented<HonClimate> {
public:
VerticalAirflowSelect() = default;

protected:
void control(const std::string &value) override;
};

} // namespace haier
} // namespace esphome
49 changes: 3 additions & 46 deletions configs/select/airflow_horizontal.yaml
Original file line number Diff line number Diff line change
@@ -1,47 +1,4 @@
select:
- platform: template
id: ${device_id}_horizontal_direction
name: ${device_name} airflow horizontal
entity_category: config
icon: mdi:arrow-expand-horizontal
update_interval: 5s
options:
- Max Left
- Left
- Center
- Right
- Max Right
- Auto
lambda: >-
switch (id(${device_id}).get_horizontal_airflow().value_or(esphome::haier::hon_protocol::HorizontalSwingMode::CENTER))
{
case esphome::haier::hon_protocol::HorizontalSwingMode::MAX_LEFT:
return std::string("Max Left");
case esphome::haier::hon_protocol::HorizontalSwingMode::LEFT:
return std::string("Left");
default:
case esphome::haier::hon_protocol::HorizontalSwingMode::CENTER:
return std::string("Center");
case esphome::haier::hon_protocol::HorizontalSwingMode::RIGHT:
return std::string("Right");
case esphome::haier::hon_protocol::HorizontalSwingMode::MAX_RIGHT:
return std::string("Max Right");
case esphome::haier::hon_protocol::HorizontalSwingMode::AUTO:
return std::string("Auto");
}
set_action:
- climate.haier.set_horizontal_airflow:
id: ${device_id}
horizontal_airflow: !lambda >-
if (x == "Max Left")
return esphome::haier::hon_protocol::HorizontalSwingMode::MAX_LEFT;
else if (x == "Left")
return esphome::haier::hon_protocol::HorizontalSwingMode::LEFT;
else if (x == "Right")
return esphome::haier::hon_protocol::HorizontalSwingMode::RIGHT;
else if (x == "Max Right")
return esphome::haier::hon_protocol::HorizontalSwingMode::MAX_RIGHT;
else if (x == "Auto")
return esphome::haier::hon_protocol::HorizontalSwingMode::AUTO;
else
return esphome::haier::hon_protocol::HorizontalSwingMode::CENTER;
- platform: haier
horizontal_airflow:
name: ${device_name} airflow horizontal
Loading