Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into cm-water-target
Browse files Browse the repository at this point in the history
  • Loading branch information
Mongey committed Feb 26, 2024
2 parents e5f55dd + 8fc4ce9 commit bad9a1e
Show file tree
Hide file tree
Showing 13 changed files with 492 additions and 189 deletions.
210 changes: 194 additions & 16 deletions components/samsung_ac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@
DEVICE_CLASS_HUMIDITY,
CONF_UNIT_OF_MEASUREMENT,
CONF_DEVICE_CLASS,
CONF_FILTERS,
UNIT_CELSIUS,
UNIT_PERCENT,
)
from esphome.core import CORE
from esphome.core import (
CORE,
Lambda
)

CODEOWNERS = ["matthias882", "lanwin"]
DEPENDENCIES = ["uart"]
Expand Down Expand Up @@ -47,46 +51,151 @@
CONF_DEVICE_ID = "samsung_ac_device_id"
CONF_DEVICE_ADDRESS = "address"
CONF_DEVICE_ROOM_TEMPERATURE = "room_temperature"
CONF_DEVICE_ROOM_HUMIDITY = "room_humidity"
CONF_DEVICE_ROOM_TEMPERATURE_OFFSET = "room_temperature_offset"
CONF_DEVICE_TARGET_TEMPERATURE = "target_temperature"
CONF_DEVICE_WATER_TEMPERATURE = "water_temperature"
CONF_DEVICE_WATER_TARGET_TEMPERATURE = "water_target_temperature"
CONF_DEVICE_OUTDOOR_TEMPERATURE = "outdoor_temperature"
CONF_DEVICE_POWER = "power"
CONF_DEVICE_MODE = "mode"
CONF_DEVICE_CLIMATE = "climate"
CONF_DEVICE_ROOM_HUMIDITY = "room_humidity"
CONF_DEVICE_WATER_TEMPERATURE = "water_temperature"
CONF_DEVICE_WATER_TARGET_TEMPERATURE = "water_target_temperature"
CONF_DEVICE_CUSTOM = "custom_sensor"
CONF_DEVICE_CUSTOM_MESSAGE = "message"
CONF_DEVICE_CUSTOM_RAW_FILTERS = "raw_filters"

CONF_CAPABILITIES = "capabilities"
CONF_CAPABILITIES_HORIZONTAL_SWING = "horizontal_swing"
CONF_CAPABILITIES_VERTICAL_SWING = "vertical_swing"

CONF_PRESETS = "presets"
CONF_PRESET_NAME = "name"
CONF_PRESET_ENABLED = "enabled"
CONF_PRESET_VALUE = "value"


def preset_entry(
name: str,
value: int,
displayName: str
): return (
cv.Optional(name, default=False), cv.Any(cv.boolean, cv.All({
cv.Optional(CONF_PRESET_ENABLED, default=False): cv.boolean,
cv.Optional(CONF_PRESET_NAME, default=displayName): cv.string,
cv.Optional(CONF_PRESET_VALUE, default=value): cv.int_
}))
)


PRESETS = {
"sleep": {"value": 1, "displayName": "Sleep"},
"quiet": {"value": 2, "displayName": "Quiet"},
"fast": {"value": 3, "displayName": "Fast"},
"longreach": {"value": 6, "displayName": "LongReach"},
"windfree": {"value": 9, "displayName": "WindFree"},
}

CAPABILITIES_SCHEMA = (
cv.Schema({
cv.Optional(CONF_CAPABILITIES_HORIZONTAL_SWING, default=False): cv.boolean,
cv.Optional(CONF_CAPABILITIES_VERTICAL_SWING, default=False): cv.boolean,
cv.Optional(CONF_PRESETS): cv.Schema(dict(
[preset_entry(name, PRESETS[name]["value"],
PRESETS[name]["displayName"]) for name in PRESETS]
))
})
)

CUSTOM_SENSOR_SCHEMA = sensor.sensor_schema().extend({
cv.Required(CONF_DEVICE_CUSTOM_MESSAGE): cv.hex_int,
})


def custom_sensor_schema(
message: int,
unit_of_measurement: str = sensor._UNDEF,
icon: str = sensor._UNDEF,
accuracy_decimals: int = sensor._UNDEF,
device_class: str = sensor._UNDEF,
state_class: str = sensor._UNDEF,
entity_category: str = sensor._UNDEF,
raw_filters=[]
):
return sensor.sensor_schema(
unit_of_measurement=unit_of_measurement,
icon=icon,
accuracy_decimals=accuracy_decimals,
device_class=device_class,
state_class=state_class,
entity_category=entity_category,
).extend({
cv.Optional(CONF_DEVICE_CUSTOM_MESSAGE, default=message): cv.hex_int,
cv.Optional(CONF_DEVICE_CUSTOM_RAW_FILTERS, default=raw_filters): sensor.validate_filters
})


def temperature_sensor_schema(message: int):
return custom_sensor_schema(
message=message,
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
raw_filters=[
{"lambda": Lambda("return (int16_t)x;")},
{"multiply": 0.1}
],
)


def humidity_sensor_schema(message: int):
return custom_sensor_schema(
message=message,
unit_of_measurement=UNIT_PERCENT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
)


DEVICE_SCHEMA = (
cv.Schema(
{
cv.GenerateID(CONF_DEVICE_ID): cv.declare_id(Samsung_AC_Device),
cv.Optional(CONF_CAPABILITIES): CAPABILITIES_SCHEMA,
cv.Required(CONF_DEVICE_ADDRESS): cv.string,
cv.Optional(CONF_DEVICE_ROOM_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_DEVICE_WATER_TEMPERATURE): sensor.sensor_schema(
cv.Optional(CONF_DEVICE_ROOM_TEMPERATURE_OFFSET): cv.float_,
cv.Optional(CONF_DEVICE_OUTDOOR_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_DEVICE_ROOM_HUMIDITY): sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_DEVICE_TARGET_TEMPERATURE): NUMBER_SCHEMA,
cv.Optional(CONF_DEVICE_WATER_TARGET_TEMPERATURE): NUMBER_SCHEMA,
cv.Optional(CONF_DEVICE_POWER): switch.switch_schema(Samsung_AC_Switch),
cv.Optional(CONF_DEVICE_MODE): SELECT_MODE_SCHEMA,
cv.Optional(CONF_DEVICE_CLIMATE): CLIMATE_SCHEMA,
cv.Optional(CONF_DEVICE_CUSTOM, default=[]): cv.ensure_list(CUSTOM_SENSOR_SCHEMA),

# keep CUSTOM_SENSOR_KEYS in sync with these
cv.Optional(CONF_DEVICE_WATER_TEMPERATURE): temperature_sensor_schema(0x4237),
cv.Optional(CONF_DEVICE_ROOM_HUMIDITY): humidity_sensor_schema(0x4038),
}
)
)

CUSTOM_SENSOR_KEYS = [
CONF_DEVICE_WATER_TEMPERATURE,
CONF_DEVICE_ROOM_HUMIDITY,
]

CONF_DEVICES = "devices"

CONF_DEBUG_MQTT_HOST = "debug_mqtt_host"
Expand All @@ -108,6 +217,7 @@
cv.Optional(CONF_DEBUG_MQTT_PASSWORD, default=""): cv.string,
cv.Optional(CONF_DEBUG_LOG_MESSAGES, default=False): cv.boolean,
cv.Optional(CONF_DEBUG_LOG_MESSAGES_RAW, default=False): cv.boolean,
cv.Optional(CONF_CAPABILITIES): CAPABILITIES_SCHEMA,
cv.Required(CONF_DEVICES): cv.ensure_list(DEVICE_SCHEMA),
}
)
Expand All @@ -126,6 +236,53 @@ async def to_code(config):
var_dev = cg.new_Pvariable(
device[CONF_DEVICE_ID], device[CONF_DEVICE_ADDRESS], var)

# setup capabilities
if CONF_CAPABILITIES in device and CONF_CAPABILITIES_VERTICAL_SWING in device[CONF_CAPABILITIES]:
cg.add(var_dev.set_supports_vertical_swing(
device[CONF_CAPABILITIES][CONF_CAPABILITIES_VERTICAL_SWING]))
elif CONF_CAPABILITIES in config and CONF_CAPABILITIES_VERTICAL_SWING in config[CONF_CAPABILITIES]:
cg.add(var_dev.set_supports_vertical_swing(
config[CONF_CAPABILITIES][CONF_CAPABILITIES_VERTICAL_SWING]))

if CONF_CAPABILITIES in device and CONF_CAPABILITIES_HORIZONTAL_SWING in device[CONF_CAPABILITIES]:
cg.add(var_dev.set_supports_horizontal_swing(
device[CONF_CAPABILITIES][CONF_CAPABILITIES_HORIZONTAL_SWING]))
elif CONF_CAPABILITIES in config and CONF_CAPABILITIES_HORIZONTAL_SWING in config[CONF_CAPABILITIES]:
cg.add(var_dev.set_supports_horizontal_swing(
config[CONF_CAPABILITIES][CONF_CAPABILITIES_HORIZONTAL_SWING]))

none_added = False
for preset in PRESETS:
device_preset_conf = device[CONF_CAPABILITIES][CONF_PRESETS][preset] if (
CONF_CAPABILITIES in device
and CONF_PRESETS in device[CONF_CAPABILITIES]
and preset in device[CONF_CAPABILITIES][CONF_PRESETS]) else None
global_preset_conf = config[CONF_CAPABILITIES][CONF_PRESETS][preset] if (
CONF_CAPABILITIES in config
and CONF_PRESETS in config[CONF_CAPABILITIES]
and preset in config[CONF_CAPABILITIES][CONF_PRESETS]) else None

preset_conf = global_preset_conf if device_preset_conf is None else device_preset_conf
preset_dict = isinstance(preset_conf, dict)
if preset_conf == True or (preset_dict and preset_conf[CONF_PRESET_ENABLED] == True):
if not none_added:
none_added = True
cg.add(var_dev.add_alt_mode("None", 0))

cg.add(var_dev.add_alt_mode(
preset_conf[CONF_PRESET_NAME] if preset_dict and CONF_PRESET_NAME in preset_conf else PRESETS[preset]["displayName"],
preset_conf[CONF_PRESET_VALUE] if preset_dict and CONF_PRESET_VALUE in preset_conf else PRESETS[preset]["value"]
))

# if CONF_CAPABILITIES in device and CONF_ALT_MODES in device[CONF_CAPABILITIES]:
# cg.add(var_dev.add_alt_mode("None", 0))
# for alt in device[CONF_CAPABILITIES][CONF_ALT_MODES]:
# cg.add(var_dev.add_alt_mode(alt[CONF_ALT_MODE_NAME], alt[CONF_ALT_MODE_VALUE]))
# elif CONF_CAPABILITIES in config and CONF_ALT_MODES in config[CONF_CAPABILITIES]:
# cg.add(var_dev.add_alt_mode("None", 0))
# for alt in config[CONF_CAPABILITIES][CONF_ALT_MODES]:
# cg.add(var_dev.add_alt_mode(alt[CONF_ALT_MODE_NAME], alt[CONF_ALT_MODE_VALUE]))

if CONF_DEVICE_POWER in device:
conf = device[CONF_DEVICE_POWER]
sens = await switch.new_switch(conf)
Expand All @@ -136,10 +293,9 @@ async def to_code(config):
sens = await sensor.new_sensor(conf)
cg.add(var_dev.set_room_temperature_sensor(sens))

if CONF_DEVICE_WATER_TEMPERATURE in device:
conf = device[CONF_DEVICE_WATER_TEMPERATURE]
sens = await sensor.new_sensor(conf)
cg.add(var_dev.set_water_temperature_sensor(sens))
if CONF_DEVICE_ROOM_TEMPERATURE_OFFSET in device:
cg.add(var_dev.set_room_temperature_offset(
device[CONF_DEVICE_ROOM_TEMPERATURE_OFFSET]))

if CONF_DEVICE_WATER_TARGET_TEMPERATURE in device:
conf = device[CONF_DEVICE_WATER_TARGET_TEMPERATURE]
Expand All @@ -154,7 +310,12 @@ async def to_code(config):
if CONF_DEVICE_ROOM_HUMIDITY in device:
conf = device[CONF_DEVICE_ROOM_HUMIDITY]
sens = await sensor.new_sensor(conf)
cg.add(var_dev.set_room_humidity_sensor(sens))
cg.add(var_dev.set_outdoor_temperature_sensor(sens))

if CONF_DEVICE_OUTDOOR_TEMPERATURE in device:
conf = device[CONF_DEVICE_OUTDOOR_TEMPERATURE]
sens = await sensor.new_sensor(conf)
cg.add(var_dev.set_outdoor_temperature_sensor(sens))

if CONF_DEVICE_TARGET_TEMPERATURE in device:
conf = device[CONF_DEVICE_TARGET_TEMPERATURE]
Expand All @@ -178,6 +339,23 @@ async def to_code(config):
await climate.register_climate(var_cli, conf)
cg.add(var_dev.set_climate(var_cli))

if CONF_DEVICE_CUSTOM in device:
for cust_sens in device[CONF_DEVICE_CUSTOM]:
sens = await sensor.new_sensor(cust_sens)
cg.add(var_dev.add_custom_sensor(
cust_sens[CONF_DEVICE_CUSTOM_MESSAGE], sens))

for key in CUSTOM_SENSOR_KEYS:
if key in device:
conf = device[key]
# combine raw filters with any user-defined filters
conf_copy = conf.copy()
conf_copy[CONF_FILTERS] = (conf[CONF_DEVICE_CUSTOM_RAW_FILTERS] if CONF_DEVICE_CUSTOM_RAW_FILTERS in conf else [
]) + (conf[CONF_FILTERS] if CONF_FILTERS in conf else [])
sens = await sensor.new_sensor(conf_copy)
cg.add(var_dev.add_custom_sensor(
conf[CONF_DEVICE_CUSTOM_MESSAGE], sens))

cg.add(var.register_device(var_dev))

cg.add(var.set_debug_mqtt(config[CONF_DEBUG_MQTT_HOST], config[CONF_DEBUG_MQTT_PORT],
Expand Down
76 changes: 33 additions & 43 deletions components/samsung_ac/conversions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,59 +128,49 @@ namespace esphome
return FanMode::Auto;
}

AltMode preset_to_altmode(climate::ClimatePreset preset)
AltModeName preset_to_altmodename(climate::ClimatePreset preset)
{
switch (preset)
{
case climate::ClimatePreset::CLIMATE_PRESET_ECO:
return "Eco";
case climate::ClimatePreset::CLIMATE_PRESET_AWAY:
return "Away";
case climate::ClimatePreset::CLIMATE_PRESET_BOOST:
return "Boost";
case climate::ClimatePreset::CLIMATE_PRESET_COMFORT:
return "Comfort";
case climate::ClimatePreset::CLIMATE_PRESET_HOME:
return "Home";
case climate::ClimatePreset::CLIMATE_PRESET_SLEEP:
return AltMode::Sleep;
return "Sleep";
case climate::ClimatePreset::CLIMATE_PRESET_ACTIVITY:
return "Activity";
case climate::ClimatePreset::CLIMATE_PRESET_NONE:
default:
return AltMode::None;
return "None";
}
}

AltMode custompreset_to_altmode(const std::string &value)
optional<climate::ClimatePreset> altmodename_to_preset(const AltModeName& name)
{
if (value == "Quiet")
return AltMode::Quiet;
if (value == "Fast")
return AltMode::Fast;
if (value == "Long Reach")
return AltMode::LongReach;
if (value == "WindFree")
return AltMode::Windfree;
return AltMode::Unknown;
}

optional<climate::ClimatePreset> altmode_to_preset(AltMode mode)
{
switch (mode)
{
case AltMode::None:
return climate::ClimatePreset::CLIMATE_PRESET_NONE;
case AltMode::Sleep:
return climate::ClimatePreset::CLIMATE_PRESET_SLEEP;
default:
return nullopt;
};
}

std::string altmode_to_custompreset(AltMode mode)
{
switch (mode)
{
case AltMode::Quiet:
return "Quiet";
case AltMode::Fast:
return "Fast";
case AltMode::LongReach:
return "Long Reach";
case AltMode::Windfree:
return "WindFree";
default:
return "";
};
if (str_equals_case_insensitive(name, "ECO"))
return optional<climate::ClimatePreset>(climate::CLIMATE_PRESET_ECO);
if (str_equals_case_insensitive(name, "AWAY"))
return optional<climate::ClimatePreset>(climate::CLIMATE_PRESET_AWAY);
if (str_equals_case_insensitive(name, "BOOST"))
return optional<climate::ClimatePreset>(climate::CLIMATE_PRESET_BOOST);
if (str_equals_case_insensitive(name, "COMFORT"))
return optional<climate::ClimatePreset>(climate::CLIMATE_PRESET_COMFORT);
if (str_equals_case_insensitive(name, "HOME"))
return optional<climate::ClimatePreset>(climate::CLIMATE_PRESET_HOME);
if (str_equals_case_insensitive(name, "SLEEP"))
return optional<climate::ClimatePreset>(climate::CLIMATE_PRESET_SLEEP);
if (str_equals_case_insensitive(name, "ACTIVITY"))
return optional<climate::ClimatePreset>(climate::CLIMATE_PRESET_ACTIVITY);
if (str_equals_case_insensitive(name, "NONE"))
return optional<climate::ClimatePreset>(climate::CLIMATE_PRESET_NONE);
return nullopt;
}

climate::ClimateSwingMode swingmode_to_climateswingmode(SwingMode swingMode)
Expand Down
6 changes: 2 additions & 4 deletions components/samsung_ac/conversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ namespace esphome
FanMode climatefanmode_to_fanmode(climate::ClimateFanMode fanmode);
FanMode customfanmode_to_fanmode(const std::string &value);

optional<climate::ClimatePreset> altmode_to_preset(AltMode mode);
std::string altmode_to_custompreset(AltMode mode);
AltMode preset_to_altmode(climate::ClimatePreset preset);
AltMode custompreset_to_altmode(const std::string &value);
AltModeName preset_to_altmodename(climate::ClimatePreset preset);
optional<climate::ClimatePreset> altmodename_to_preset(const AltModeName& name);

climate::ClimateSwingMode swingmode_to_climateswingmode(SwingMode swingMode);
SwingMode climateswingmode_to_swingmode(climate::ClimateSwingMode swingMode);
Expand Down
Loading

0 comments on commit bad9a1e

Please sign in to comment.