Skip to content

Commit

Permalink
Merge pull request rbroker#11 from limkinZero/main
Browse files Browse the repository at this point in the history
Allow control cool modes from HA
  • Loading branch information
rbroker committed Nov 11, 2023
2 parents 163fb61 + 39e7491 commit fa59f02
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 47 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ The GPIO pin number which should be used for the status LED. The following flash
| ----------- | -------- |
| LED_BUILTIN | No |

### Heat Pump Configuration
Some parameters of your Mitsubishi Ecodan HVAC
| Parameter | Description | Default |
| ----------- | ------------| -------- |
| `Cool enabled` | Check this option if your ecodan has cool working mode. Enable setting cool mode from Home Assistant | False |

### Dump Serial Packets
Dump packets sent to/received from the heat pump to the diagnostic log window on the Diagnostics page.

Expand Down Expand Up @@ -138,6 +144,7 @@ The topic value which the server should use to filter messages related to this h
| ----------- | -------- |
| `ecodan_hp` | Yes |


## See Also
There are a number of existing solutions for connecting to Mitsubish heat pump models via the CN105 connector, I wouldn't have been able to put this together without work already done here:
- https://github.com/m000c400/Mitsubishi-CN105-Protocol-Decode
Expand Down
6 changes: 4 additions & 2 deletions ecodan-ha-local/ehal_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace ehal
config.SerialTxPort = prefs.getUShort("serial_tx", 26U);
config.StatusLed = prefs.getUShort("status_led", LED_BUILTIN);
config.DumpPackets = prefs.getBool("dump_pkt", false);
config.CoolEnabled = prefs.getBool("cool_enabled", false);
config.HostName = prefs.getString("hostname", "ecodan_ha_local");
config.WifiSsid = prefs.getString("wifi_ssid");
config.WifiPassword = prefs.getString("wifi_pw");
Expand All @@ -48,7 +49,8 @@ namespace ehal
prefs.putUShort("serial_rx", config.SerialRxPort);
prefs.putUShort("serial_tx", config.SerialTxPort);
prefs.putUShort("status_led", config.StatusLed);
prefs.putBool("dump_pkt", config.DumpPackets);
prefs.putBool("dump_pkt", config.DumpPackets);
prefs.putBool("cool_enabled", config.CoolEnabled);
prefs.putString("wifi_ssid", config.WifiSsid);
prefs.putString("wifi_pw", config.WifiPassword);
prefs.putString("hostname", config.HostName);
Expand Down Expand Up @@ -80,7 +82,7 @@ namespace ehal

String get_software_version()
{
return FPSTR("v0.1.1");
return FPSTR("v0.1.2");
}

} // namespace ehal
1 change: 1 addition & 0 deletions ecodan-ha-local/ehal_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace ehal
uint16_t SerialTxPort;
uint16_t StatusLed;
bool DumpPackets;
bool CoolEnabled;
String WifiSsid;
String WifiPassword;
String HostName;
Expand Down
8 changes: 4 additions & 4 deletions ecodan-ha-local/ehal_hp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,10 @@ namespace ehal::hp
return true;
}

bool set_sh_mode(uint8_t mode)
bool set_hp_mode(uint8_t mode)
{
Message cmd{MsgType::SET_CMD, SetType::BASIC_SETTINGS};
cmd[1] = SET_SETTINGS_FLAG_HEATING_MODE;
cmd[1] = SET_SETTINGS_FLAG_HP_MODE;
cmd[6] = mode;

{
Expand All @@ -398,7 +398,7 @@ namespace ehal::hp

if (!dispatch_next_cmd())
{
log_web(F("command dispatch failed for DHW force setting!"));
log_web(F("command dispatch failed for heat pump mode setting!"));
return false;
}

Expand Down Expand Up @@ -465,7 +465,7 @@ namespace ehal::hp
status.set_power_mode(res[3]);
status.set_operation_mode(res[4]);
status.set_dhw_mode(res[5]);
status.set_heating_mode(res[6]);
status.set_heating_cooling_mode(res[6]);
status.DhwFlowTemperatureSetPoint = res.get_float16(8);
status.RadiatorFlowTemperatureSetPoint = res.get_float16(12);
break;
Expand Down
64 changes: 43 additions & 21 deletions ecodan-ha-local/ehal_hp.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ namespace ehal::hp
{
OFF = 0,
DHW_ON = 1,
SH_ON = 2,
SH_ON = 2, // Heating
COOL_ON = 3, // Cooling
FROST_PROTECT = 5,
LEGIONELLA_PREVENTION = 6
};
Expand All @@ -55,11 +56,13 @@ namespace ehal::hp
ECO = 1
};

enum class ShMode : uint8_t
enum class HpMode : uint8_t
{
ROOM_TEMP = 0,
FLOW_TEMP = 1,
COMPENSATION_CURVE = 2
HEAT_ROOM_TEMP = 0,
HEAT_FLOW_TEMP = 1,
HEAT_COMPENSATION_CURVE = 2,
COOL_ROOM_TEMP = 3,
COOL_FLOW_TEMP = 4
};

// Modes
Expand All @@ -68,7 +71,7 @@ namespace ehal::hp
bool HolidayMode;
bool DhwTimerMode;
DhwMode HotWaterMode;
ShMode HeatingMode;
HpMode HeatingCoolingMode;

// Efficiency
uint8_t CompressorFrequency;
Expand All @@ -84,7 +87,19 @@ namespace ehal::hp
switch (Power)
{
case PowerMode::ON:
return F("heat");
switch (HeatingCoolingMode)
{
case HpMode::HEAT_ROOM_TEMP:
[[fallthrough]]
case HpMode::HEAT_FLOW_TEMP:
[[fallthrough]]
case HpMode::HEAT_COMPENSATION_CURVE:
return F("heat");
case HpMode::COOL_ROOM_TEMP:
[[fallthrough]]
case HpMode::COOL_FLOW_TEMP:
return F("cool");
}
default:
return F("off");
}
Expand All @@ -96,9 +111,10 @@ namespace ehal::hp
{
case OperationMode::SH_ON:
[[fallthrough]]
case OperationMode::FROST_PROTECT:
case OperationMode::FROST_PROTECT:
return F("heating");

case OperationMode::COOL_ON:
return F("cooling");
case OperationMode::OFF:
[[fallthrough]]
case OperationMode::DHW_ON:
Expand Down Expand Up @@ -129,8 +145,10 @@ namespace ehal::hp
return F("Off");
case OperationMode::DHW_ON:
return F("Heating Water");
case OperationMode::SH_ON:
case OperationMode::SH_ON:
return F("Space Heating");
case OperationMode::COOL_ON:
return F("Space Cooling");
case OperationMode::FROST_PROTECT:
return F("Frost Protection");
case OperationMode::LEGIONELLA_PREVENTION:
Expand Down Expand Up @@ -162,16 +180,20 @@ namespace ehal::hp
}
}

String heating_mode_as_string()
String hp_mode_as_string()
{
switch (HeatingMode)
switch (HeatingCoolingMode)
{
case ShMode::ROOM_TEMP:
return F("Target Temperature");
case ShMode::FLOW_TEMP:
return F("Flow Temperature");
case ShMode::COMPENSATION_CURVE:
return F("Compensation Curve");
case HpMode::HEAT_ROOM_TEMP:
return F("Heat Target Temperature");
case HpMode::HEAT_FLOW_TEMP:
return F("Heat Flow Temperature");
case HpMode::HEAT_COMPENSATION_CURVE:
return F("Heat Compensation Curve");
case HpMode::COOL_ROOM_TEMP:
return F("Cool Target Temperature");
case HpMode::COOL_FLOW_TEMP:
return F("Cool Flow Temperature");
default:
return F("Unknown");
}
Expand All @@ -192,9 +214,9 @@ namespace ehal::hp
HotWaterMode = static_cast<DhwMode>(mode);
}

void set_heating_mode(uint8_t mode)
void set_heating_cooling_mode(uint8_t mode)
{
HeatingMode = static_cast<ShMode>(mode);
HeatingCoolingMode = static_cast<HpMode>(mode);
}

void lock()
Expand Down Expand Up @@ -224,7 +246,7 @@ namespace ehal::hp
bool set_dhw_target_temperature(float value);
bool set_dhw_mode(String mode);
bool set_dhw_force(bool on);
bool set_sh_mode(uint8_t mode);
bool set_hp_mode(uint8_t mode);

bool begin_connect();
bool begin_update_status();
Expand Down
10 changes: 8 additions & 2 deletions ecodan-ha-local/ehal_html.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ namespace ehal
<input class="column column-75" type="checkbox" id="dump_pkt" name="dump_pkt" {{dump_pkt}} />
</div>
<br />
<h2>Heat Pump Configuration:</h2>
<div class="row">
<label class="column column-25" for="cool_enabled">Cool mode:</label>
<input class="column column-75" type="checkbox" id="cool_enabled" name="cool_enabled" {{cool_enabled}} />
</div>
<br />
<h2>WiFi Configuration:</h2>
<div class="row">
<label class="column column-25" for="wifi_ssid">WiFi SSID:</label>
Expand Down Expand Up @@ -306,8 +312,8 @@ namespace ehal
<td>{{mode_dhw_timer}}</td>
</tr>
<tr>
<td>Heating Mode:</td>
<td>{{mode_heating}}</td>
<td>Heating/Cooling Mode:</td>
<td>{{mode_heating_cooling}}</td>
</tr>
<tr>
<td>DHW Mode:</td>
Expand Down
13 changes: 12 additions & 1 deletion ecodan-ha-local/ehal_http.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ namespace ehal::http
else
page.replace(F("{{dump_pkt}}"), "");

// Heat pump config
if (config.CoolEnabled)
page.replace(F("{{cool_enabled}}"), F("checked"));
else
page.replace(F("{{cool_enabled}}"), "");

page.replace(F("{{wifi_ssid}}"), config.WifiSsid);
page.replace(F("{{wifi_pw}}"), config.WifiPassword);
page.replace(F("{{hostname}}"), config.HostName);
Expand Down Expand Up @@ -196,6 +202,11 @@ namespace ehal::http
config.DumpPackets = true;
else
config.DumpPackets = false;

if (server.hasArg(F("cool_enabled")))
config.CoolEnabled = true;
else
config.CoolEnabled = false;

config.WifiSsid = server.arg(F("wifi_ssid"));
config.WifiPassword = server.arg(F("wifi_pw"));
Expand Down Expand Up @@ -376,7 +387,7 @@ namespace ehal::http
page.replace(F("{{defrost}}"), bool_to_emoji(status.DefrostActive));
page.replace(F("{{dhw_forced}}"), bool_to_emoji(status.DhwForcedActive));
page.replace(F("{{mode_dhw_timer}}"), bool_to_emoji(status.DhwTimerMode));
page.replace(F("{{mode_heating}}"), status.heating_mode_as_string());
page.replace(F("{{mode_heating_cooling}}"), status.hp_mode_as_string());
page.replace(F("{{mode_dhw}}"), status.dhw_mode_as_string());

page.replace(F("{{min_flow_temp}}"), String(status.MinimumFlowTemperature));
Expand Down
45 changes: 29 additions & 16 deletions ecodan-ha-local/ehal_mqtt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,35 +165,44 @@ off
void on_mode_set_command(const String& payload)
{
uint8_t mode = -1;
if (payload == "Target Temperature")

if (payload == "Heat Target Temperature")
{
mode = static_cast<uint8_t>(hp::Status::HpMode::HEAT_ROOM_TEMP);
}
else if (payload == "Heat Flow Temperature")
{
mode = static_cast<uint8_t>(hp::Status::ShMode::ROOM_TEMP);
mode = static_cast<uint8_t>(hp::Status::HpMode::HEAT_FLOW_TEMP);
}
else if (payload == "Flow Temperature")
else if (payload == "Heat Compensation Curve")
{
mode = static_cast<uint8_t>(hp::Status::ShMode::FLOW_TEMP);
mode = static_cast<uint8_t>(hp::Status::HpMode::HEAT_COMPENSATION_CURVE);
}
else if (payload == "Compensation Curve")
else if (payload == "Cool Target Temperature")
{
mode = static_cast<uint8_t>(hp::Status::ShMode::COMPENSATION_CURVE);
mode = static_cast<uint8_t>(hp::Status::HpMode::COOL_ROOM_TEMP);
}
else if (payload == "Cool Flow Temperature")
{
mode = static_cast<uint8_t>(hp::Status::HpMode::COOL_FLOW_TEMP);
}
else
{
log_web(F("Unexpected mode requested: %s"), payload.c_str());
return;
}

if (!hp::set_sh_mode(mode))
if (!hp::set_hp_mode(mode))
{
log_web(F("Failed to set space heating operation mode!"));
log_web(F("Failed to set hp heating coling operation mode!"));
}
else
{
auto& status = hp::get_status();
std::lock_guard<hp::Status> lock{status};
status.set_heating_mode(mode);
status.set_heating_cooling_mode(mode);

publish_sensor_status<String>(F("mode_heating"), status.heating_mode_as_string());
publish_sensor_status<String>(F("mode_heating_cooling"), status.hp_mode_as_string());
}
}

Expand Down Expand Up @@ -507,12 +516,16 @@ off

add_discovery_device_object(payloadJson);

payloadJson[F("stat_t")] = config.MqttTopic + "/" + unique_entity_name(F("mode_heating")) + F("/state");
payloadJson[F("stat_t")] = config.MqttTopic + "/" + unique_entity_name(F("mode_heating_cooling")) + F("/state");
payloadJson[F("cmd_t")] = config.MqttTopic + "/" + unique_entity_name(F("sh_mode")) + F("/set");
JsonArray options = payloadJson.createNestedArray(F("options"));
options.add("Target Temperature");
options.add("Flow Temperature");
options.add("Compensation Curve");
options.add("Heat Target Temperature");
options.add("Heat Flow Temperature");
options.add("Heat Compensation Curve");
if (config.CoolEnabled) {
options.add("Cool Target Temperature");
options.add("Cool Flow Temperature");
}

if (!publish_mqtt(discoveryTopic, payloadJson, /* retain =*/true))
{
Expand Down Expand Up @@ -723,7 +736,7 @@ off
if (!publish_ha_string_sensor_auto_discover(F("mode_dhw")))
anyFailed = true;

if (!publish_ha_string_sensor_auto_discover(F("mode_heating")))
if (!publish_ha_string_sensor_auto_discover(F("mode_heating_cooling")))
anyFailed = true;

if (!publish_ha_float_sensor_auto_discover(F("heating_consumed"), SensorType::POWER))
Expand Down Expand Up @@ -821,7 +834,7 @@ off
publish_sensor_status<String>(F("mode_power"), status.power_as_string());
publish_sensor_status<String>(F("mode_operation"), status.operation_as_string());
publish_sensor_status<String>(F("mode_dhw"), status.dhw_mode_as_string());
publish_sensor_status<String>(F("mode_heating"), status.heating_mode_as_string());
publish_sensor_status<String>(F("mode_heating_cooling"), status.hp_mode_as_string());
publish_sensor_status<float>(F("heating_consumed"), status.EnergyConsumedHeating);
publish_sensor_status<float>(F("heating_delivered"), status.EnergyDeliveredHeating);
publish_sensor_status<float>(F("dhw_consumed"), status.EnergyConsumedDhw);
Expand Down
2 changes: 1 addition & 1 deletion ecodan-ha-local/ehal_proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace ehal::hp

#define SET_SETTINGS_FLAG_ZONE_TEMPERATURE 0x80
#define SET_SETTINGS_FLAG_DHW_TEMPERATURE 0x20
#define SET_SETTINGS_FLAG_HEATING_MODE 0x08
#define SET_SETTINGS_FLAG_HP_MODE 0x08
#define SET_SETTINGS_FLAG_DHW_MODE 0x04
#define SET_SETTINGS_FLAG_MODE_TOGGLE 0x1

Expand Down

0 comments on commit fa59f02

Please sign in to comment.