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

feat: Add error code sensor #18

Merged
merged 8 commits into from
Apr 2, 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
12 changes: 9 additions & 3 deletions components/mitsubishi_uart/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import climate, uart, sensor, binary_sensor, select, switch
from esphome.components import climate, uart, sensor, binary_sensor, text_sensor, select, switch
from esphome.core import CORE
from esphome.const import (
CONF_ID,
Expand All @@ -19,14 +19,15 @@
)
from esphome.core import coroutine

AUTO_LOAD = ["climate", "select", "sensor", "binary_sensor", "switch"]
DEPENDENCIES = ["uart", "climate", "sensor", "binary_sensor", "select", "switch"]
AUTO_LOAD = ["climate", "select", "sensor", "binary_sensor", "text_sensor", "switch"]
DEPENDENCIES = ["uart", "climate", "sensor", "binary_sensor", "text_sensor", "select", "switch"]

CONF_HP_UART = "heatpump_uart"
CONF_TS_UART = "thermostat_uart"

CONF_SENSORS = "sensors"
CONF_SENSORS_THERMOSTAT_TEMP = "thermostat_temperature"
CONF_SENSORS_ERROR_CODE = "error_code"

CONF_SELECTS = "selects"
CONF_TEMPERATURE_SOURCE_SELECT = "temperature_source_select" # This is to create a Select object for selecting a source
Expand Down Expand Up @@ -125,6 +126,11 @@
binary_sensor.binary_sensor_schema(),
binary_sensor.register_binary_sensor
),
CONF_SENSORS_ERROR_CODE: (
"Error Code",
text_sensor.text_sensor_schema(),
text_sensor.register_text_sensor
)
}

SENSORS_SCHEMA = cv.All({
Expand Down
26 changes: 22 additions & 4 deletions components/mitsubishi_uart/mitsubishi_uart-packetprocessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,31 @@ void MitsubishiUART::processPacket(const StandbyGetResponsePacket &packet) {
}

//TODO: Not sure what AutoMode does yet
};
}

void MitsubishiUART::processPacket(const ErrorStateGetResponsePacket &packet) {
ESP_LOGV(TAG, "Processing %s", packet.to_string().c_str());
routePacket(packet);
// TODO: The MHK2 thermostat often asks for this, but the response is usually just all zeros. Could be be checking for
// errors / messages / warnings. Should check when e.g. the filter life runs out.
};

std::string oldErrorCode = error_code_sensor->raw_state;

// TODO: Include friendly text from JSON, somehow.
if (!packet.errorPresent()) {
error_code_sensor->raw_state = "No Error Reported";
} else if (auto rawCode = packet.getRawShortCode() != 0x00) {
// Not that it matters, but good for validation I guess.
if ((rawCode & 0x1F) > 0x15) {
ESP_LOGW(TAG, "Error short code %x had invalid low bits. This is an IT protocol violation!", rawCode);
}

error_code_sensor->raw_state = "Error " + packet.getShortCode();
} else {
error_code_sensor->raw_state = "Error " + to_string(packet.getErrorCode());
}

publishOnUpdate |= (oldErrorCode != error_code_sensor->raw_state);
}

void MitsubishiUART::processPacket(const RemoteTemperatureSetRequestPacket &packet) {
ESP_LOGV(TAG, "Processing %s", packet.to_string().c_str());

Expand Down
9 changes: 8 additions & 1 deletion components/mitsubishi_uart/mitsubishi_uart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ be about `update_interval` late from their actual time. Generally the update in
(default is 5seconds) this won't pose a practical problem.
*/
void MitsubishiUART::update() {

// TODO: Temporarily wait 5 seconds on startup to help with viewing logs
if (millis() < 5000) {
return;
Expand All @@ -128,10 +127,14 @@ void MitsubishiUART::update() {

IFACTIVE(
// Request an update from the heatpump
// TODO: This isn't a problem *yet*, but sending all these packets every loop might start to cause some issues in
// certain configurations or setups. We may want to consider only asking for certain packets on a rarer cadence,
// depending on their utility (e.g. we dont need to check for errors every loop).
hp_bridge.sendPacket(GetRequestPacket::getSettingsInstance()); // Needs to be done before status packet for mode logic to work
hp_bridge.sendPacket(GetRequestPacket::getStandbyInstance());
hp_bridge.sendPacket(GetRequestPacket::getStatusInstance());
hp_bridge.sendPacket(GetRequestPacket::getCurrentTempInstance());
hp_bridge.sendPacket(GetRequestPacket::getErrorInfoInstance());
)
}

Expand All @@ -157,6 +160,10 @@ void MitsubishiUART::doPublish() {
ESP_LOGI(TAG, "Actual fan speed differs, do publish");
actual_fan_sensor->publish_state(actual_fan_sensor->raw_state);
}
if (error_code_sensor && (error_code_sensor->raw_state != error_code_sensor->state)) {
ESP_LOGI(TAG, "Error code state differs, do publish");
error_code_sensor->publish_state(error_code_sensor->raw_state);
}

// Binary sensors automatically dedup publishes (I think) and so will only actually publish on change
service_filter_sensor->publish_state(service_filter_sensor->state);
Expand Down
2 changes: 2 additions & 0 deletions components/mitsubishi_uart/mitsubishi_uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class MitsubishiUART : public PollingComponent, public climate::Climate, public
void set_defrost_sensor(binary_sensor::BinarySensor *sensor) {defrost_sensor = sensor;};
void set_hot_adjust_sensor(binary_sensor::BinarySensor *sensor) {hot_adjust_sensor = sensor;};
void set_standby_sensor(binary_sensor::BinarySensor *sensor) {standby_sensor = sensor;};
void set_error_code_sensor(text_sensor::TextSensor *sensor) { error_code_sensor = sensor; };

// Select setters
void set_temperature_source_select(select::Select *select) {temperature_source_select = select;};
Expand Down Expand Up @@ -150,6 +151,7 @@ class MitsubishiUART : public PollingComponent, public climate::Climate, public
binary_sensor::BinarySensor *defrost_sensor = nullptr;
binary_sensor::BinarySensor *hot_adjust_sensor = nullptr;
binary_sensor::BinarySensor *standby_sensor = nullptr;
text_sensor::TextSensor *error_code_sensor = nullptr;

// Selects
select::Select *temperature_source_select;
Expand Down
2 changes: 1 addition & 1 deletion components/mitsubishi_uart/muart_bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ void MUARTBridge::classifyAndProcessRawPacket(RawPacket &pkt) const {
case GetCommand::current_temp :
processRawPacket<CurrentTempGetResponsePacket>(pkt, false);
break;
case GetCommand::four :
case GetCommand::error_info :
processRawPacket<ErrorStateGetResponsePacket>(pkt, false);
break;
case GetCommand::standby :
Expand Down
22 changes: 20 additions & 2 deletions components/mitsubishi_uart/muart_packet-derived.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "muart_packet.h"
#include "muart_utils.h"
#include "mitsubishi_uart.h"

namespace esphome {
namespace mitsubishi_uart {
Expand Down Expand Up @@ -75,8 +76,9 @@ std::string StatusGetResponsePacket::to_string() const {
std::string ErrorStateGetResponsePacket::to_string() const {
return ("Error State Response: " + Packet::to_string()
+ CONSOLE_COLOR_PURPLE
+ "\n ErrorCode: " + format_hex(getErrorCode())
+ " ShortCode: " + format_hex(getShortCode()) // TODO: This can be converted to a code string
+ "\n Error State: " + (errorPresent() ? "Yes" : "No")
+ " ErrorCode: " + format_hex(getErrorCode())
+ " ShortCode: " + getShortCode() + "(" + format_hex(getRawShortCode()) + ")"
);
}
std::string RemoteTemperatureSetRequestPacket::to_string() const {
Expand Down Expand Up @@ -202,5 +204,21 @@ std::string ThermostatHelloRequestPacket::getThermostatVersionString() const {
return buf;
}

// ErrorStateGetResponsePacket functions
std::string ErrorStateGetResponsePacket::getShortCode() const {
const char* upperAlphabet = "AbEFJLPU";
const char* lowerAlphabet = "0123456789ABCDEFOHJLPU";
const uint8_t errorCode = this->getRawShortCode();

uint8_t lowBits = errorCode & 0x1F;
if (lowBits > 0x15) {
char buf[7];
sprintf(buf, "ERR_%x", errorCode);
return buf;
}

return {upperAlphabet[(errorCode & 0xE0) >> 5], lowerAlphabet[lowBits]};
}

} // namespace mitsubishi_uart
} // namespace esphome
9 changes: 8 additions & 1 deletion components/mitsubishi_uart/muart_packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ class GetRequestPacket : public Packet {
static GetRequestPacket INSTANCE = GetRequestPacket(GetCommand::status);
return INSTANCE;
}
static GetRequestPacket& getErrorInfoInstance() {
static GetRequestPacket INSTANCE = GetRequestPacket(GetCommand::error_info);
return INSTANCE;
}
using Packet::Packet;

private:
Expand Down Expand Up @@ -257,7 +261,10 @@ class ErrorStateGetResponsePacket : public Packet {
using Packet::Packet;
public:
uint16_t getErrorCode() const {return pkt_.getPayloadByte(4) << 8 | pkt_.getPayloadByte(5);}
uint8_t getShortCode() const {return pkt_.getPayloadByte(6);}
uint8_t getRawShortCode() const {return pkt_.getPayloadByte(6);}
std::string getShortCode() const;

bool errorPresent() const { return getErrorCode() != 0x8000 || getRawShortCode() != 0x00; }

std::string to_string() const override;
};
Expand Down
2 changes: 1 addition & 1 deletion components/mitsubishi_uart/muart_rawpacket.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ enum class PacketType : uint8_t {
enum class GetCommand : uint8_t {
settings = 0x02,
current_temp = 0x03,
four = 0x04,
error_info = 0x04,
status = 0x06,
standby = 0x09,
a_9 = 0xa9
Expand Down