Merge pull request #6 from ElVit/panasonic_dev
Added feature to change min/max values of entity SET5/6/7/8 depending on the current state of entity TOP76/81. Improved loop time. Added new heatpump models (taken from HeishaMon).
This commit is contained in:
commit
24e7f16f9e
|
|
@ -9,7 +9,10 @@ namespace esphome
|
||||||
0x31, 0x05, 0x10, 0x01, 0x00, 0x00, 0x00, 0xB9
|
0x31, 0x05, 0x10, 0x01, 0x00, 0x00, 0x00, 0xB9
|
||||||
};
|
};
|
||||||
const uint8_t PanasonicCommand::InitialResponse[INIT_RESPONSE_SIZE] = {
|
const uint8_t PanasonicCommand::InitialResponse[INIT_RESPONSE_SIZE] = {
|
||||||
0x31, 0x30, 0x01, 0x10, 0x1E, 0x6C, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C
|
0x31, 0x30, 0x01, 0x10, 0x1E, 0x6C, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C
|
||||||
};
|
};
|
||||||
const uint8_t PanasonicCommand::PollingMessage[DATA_MESSAGE_SIZE] = {
|
const uint8_t PanasonicCommand::PollingMessage[DATA_MESSAGE_SIZE] = {
|
||||||
0x71, 0x6C, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x71, 0x6C, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,11 @@ namespace esphome
|
||||||
{ 0xE2, 0xCF, 0x0C, 0x74, 0x09, 0x12, 0xD0, 0x0C, 0x95, 0x05 }, // 47
|
{ 0xE2, 0xCF, 0x0C, 0x74, 0x09, 0x12, 0xD0, 0x0C, 0x95, 0x05 }, // 47
|
||||||
{ 0xE2, 0xD5, 0x0B, 0x34, 0x99, 0x83, 0x92, 0x0C, 0x28, 0x98 }, // 48
|
{ 0xE2, 0xD5, 0x0B, 0x34, 0x99, 0x83, 0x92, 0x0C, 0x28, 0x98 }, // 48
|
||||||
{ 0xE2, 0xCF, 0x0D, 0x77, 0x09, 0x12, 0xD0, 0x0C, 0x05, 0x11 }, // 49
|
{ 0xE2, 0xCF, 0x0D, 0x77, 0x09, 0x12, 0xD0, 0x0C, 0x05, 0x11 }, // 49
|
||||||
|
{ 0xE2, 0xCF, 0x0B, 0x44, 0x34, 0x12, 0xD0, 0x0C, 0x34, 0x35 }, // 50
|
||||||
{ 0xE2, 0xD5, 0x0C, 0x67, 0x00, 0x83, 0x92, 0x0C, 0x27, 0x98 }, // 51
|
{ 0xE2, 0xD5, 0x0C, 0x67, 0x00, 0x83, 0x92, 0x0C, 0x27, 0x98 }, // 51
|
||||||
{ 0xE2, 0xD5, 0x0B, 0x34, 0x99, 0x83, 0x92, 0x0C, 0x27, 0x98 }, // 52
|
{ 0xE2, 0xD5, 0x0B, 0x34, 0x99, 0x83, 0x92, 0x0C, 0x27, 0x98 }, // 52
|
||||||
|
{ 0x42, 0xD4, 0x0B, 0x83, 0x71, 0x32, 0xD2, 0x0C, 0x44, 0x55 }, // 53
|
||||||
|
{ 0xE2, 0xCF, 0x0C, 0x74, 0x09, 0x12, 0xD0, 0x0E, 0x94, 0x05 }, // 54
|
||||||
};
|
};
|
||||||
|
|
||||||
int PanasonicDecode::getBit1(uint8_t input)
|
int PanasonicDecode::getBit1(uint8_t input)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define RESPONSE_MSG_SIZE 203
|
#define RESPONSE_MSG_SIZE 203
|
||||||
#define NUMBER_OF_MODELS 53
|
#define NUMBER_OF_MODELS 55
|
||||||
|
|
||||||
|
|
||||||
namespace esphome
|
namespace esphome
|
||||||
|
|
@ -60,13 +60,14 @@ namespace esphome
|
||||||
static const constexpr char* const ZonesSensorType[] = { "4", "Water Temperature", "External Thermostat", "Internal Thermostat", "Thermistor" };
|
static const constexpr char* const ZonesSensorType[] = { "4", "Water Temperature", "External Thermostat", "Internal Thermostat", "Thermistor" };
|
||||||
static const constexpr char* const Quietmode[] = { "4", "Off", "Level 1", "Level 2", "Level 3" };
|
static const constexpr char* const Quietmode[] = { "4", "Off", "Level 1", "Level 2", "Level 3" };
|
||||||
static const constexpr char* const Powerfulmode[] = { "4", "Off", "30min", "60min", "90min" };
|
static const constexpr char* const Powerfulmode[] = { "4", "Off", "30min", "60min", "90min" };
|
||||||
static const constexpr char* const OpModeDesc[] = { "11", "Heat only", "Cool only", "Auto", "Auto(heat)", "Auto(cool)", "DHW only", "Heat+DHW", "Cool+DHW", "Auto+DHW", "Auto(heat)+DHW", "Auto(cool)+DHW" };
|
static const constexpr char* const OpModeDesc[] = { "11", "Heat only", "Cool only", "Auto", "Auto(heat)", "Auto(cool)", "DHW only",
|
||||||
|
"Heat+DHW", "Cool+DHW", "Auto+DHW", "Auto(heat)+DHW", "Auto(cool)+DHW" };
|
||||||
static const constexpr char* const ZonesState[] = { "3", "Zone 1", "Zone 2", "Zone 1 & 2" };
|
static const constexpr char* const ZonesState[] = { "3", "Zone 1", "Zone 2", "Zone 1 & 2" };
|
||||||
static const constexpr char* const ExtPadHeaterType[] = { "3", "Disabled", "Type-A", "Type-B" };
|
static const constexpr char* const ExtPadHeaterType[] = { "3", "Disabled", "Type-A", "Type-B" };
|
||||||
static const constexpr char* const Bivalent[] = { "3", "Alternative", "Parallel", "Advanced Parallel" };
|
static const constexpr char* const Bivalent[] = { "3", "Alternative", "Parallel", "Advanced Parallel" };
|
||||||
static const constexpr char* const ModelNames[] =
|
static const constexpr char* const ModelNames[] =
|
||||||
{
|
{
|
||||||
"53", //string representation of number of known models (last model number + 1)
|
"55", // string representation of number of known models (last model number + 1)
|
||||||
"WH-MDC05H3E5", // 0
|
"WH-MDC05H3E5", // 0
|
||||||
"WH-MDC07H3E5", // 1
|
"WH-MDC07H3E5", // 1
|
||||||
"IDU:WH-SXC09H3E5, ODU:WH-UX09HE5", // 2
|
"IDU:WH-SXC09H3E5, ODU:WH-UX09HE5", // 2
|
||||||
|
|
@ -117,8 +118,11 @@ namespace esphome
|
||||||
"IDU:WH-ADC0916H9E8, ODU:WH-UX12HE8", // 47
|
"IDU:WH-ADC0916H9E8, ODU:WH-UX12HE8", // 47
|
||||||
"IDU:WH-SDC0509L3E5, ODU:WH-WDG07LE5", // 48
|
"IDU:WH-SDC0509L3E5, ODU:WH-WDG07LE5", // 48
|
||||||
"IDU:WH-SXC09H3E5, ODU:WH-UX09HE5", // 49
|
"IDU:WH-SXC09H3E5, ODU:WH-UX09HE5", // 49
|
||||||
|
"WH-MXC12H9E8", // 50
|
||||||
"IDU:WH-ADC0509L3E5AN, ODU:WH-WDG05LE5", // 51
|
"IDU:WH-ADC0509L3E5AN, ODU:WH-WDG05LE5", // 51
|
||||||
"IDU:WH-SDC0509L3E5, ODU:WH-WDG05LE5", // 52
|
"IDU:WH-SDC0509L3E5, ODU:WH-WDG05LE5", // 52
|
||||||
|
"IDU:WH-ADC0309J3E5C, ODU:WH-UD03JE5", // 53
|
||||||
|
"IDU:WH-ADC0916H9E8, ODU:WH-UX09HE8", // 54
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace esphome
|
||||||
|
{
|
||||||
|
namespace panasonic_heatpump
|
||||||
|
{
|
||||||
|
static const char *const TAG = "panasonic_heatpump";
|
||||||
|
|
||||||
|
void PanasonicHelpers::log_uart_hex(UartLogDirection direction, const std::vector<uint8_t>& data, const char separator)
|
||||||
|
{
|
||||||
|
PanasonicHelpers::log_uart_hex(direction, &data[0], data.size(), separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PanasonicHelpers::log_uart_hex(UartLogDirection direction, const uint8_t* data, const size_t length, const char separator)
|
||||||
|
{
|
||||||
|
std::string logStr = "";
|
||||||
|
std::string msgDir = direction == UART_LOG_TX ? ">>>" : "<<<";
|
||||||
|
std::string msgType = direction == UART_LOG_TX ? "request" : "response";
|
||||||
|
switch(data[0])
|
||||||
|
{
|
||||||
|
case 0x31:
|
||||||
|
msgType = "initial_" + msgType;
|
||||||
|
break;
|
||||||
|
case 0x71:
|
||||||
|
msgType = "polling_" + msgType;
|
||||||
|
break;
|
||||||
|
case 0xF1:
|
||||||
|
msgType = "command_" + msgType;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "%s %s[%i]", msgDir.c_str(), msgType.c_str(), length);
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
char buffer[5];
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (i > 0) logStr += separator;
|
||||||
|
sprintf(buffer, "%02X", data[i]);
|
||||||
|
logStr += buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < logStr.length(); i += UART_LOG_CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "%s %s", msgDir.c_str(), logStr.substr(i, UART_LOG_CHUNK_SIZE).c_str());
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace panasonic_heatpump
|
||||||
|
} // namespace esphome
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define UART_LOG_CHUNK_SIZE 120
|
||||||
|
|
||||||
|
|
||||||
|
namespace esphome
|
||||||
|
{
|
||||||
|
namespace panasonic_heatpump
|
||||||
|
{
|
||||||
|
enum UartLogDirection
|
||||||
|
{
|
||||||
|
UART_LOG_RX,
|
||||||
|
UART_LOG_TX,
|
||||||
|
};
|
||||||
|
|
||||||
|
class PanasonicHelpers
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void log_uart_hex(UartLogDirection direction, const std::vector<uint8_t>& data, const char separator);
|
||||||
|
static void log_uart_hex(UartLogDirection direction, const uint8_t* data, const size_t length, const char separator);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -82,10 +82,10 @@ TYPES = [
|
||||||
|
|
||||||
# min_value, max_value, step
|
# min_value, max_value, step
|
||||||
CONF_NUMBERS = [
|
CONF_NUMBERS = [
|
||||||
[ -5, 5, 1, ],
|
[ 0, 0, 1, ],
|
||||||
[ -5, 5, 1, ],
|
[ 0, 0, 1, ],
|
||||||
[ -5, 5, 1, ],
|
[ 0, 0, 1, ],
|
||||||
[ -5, 5, 1, ],
|
[ 0, 0, 1, ],
|
||||||
[ 40, 75, 1, ],
|
[ 40, 75, 1, ],
|
||||||
[ 64, 254, 1, ],
|
[ 64, 254, 1, ],
|
||||||
[ -15, 35, 1, ],
|
[ -15, 35, 1, ],
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "panasonic_heatpump.h"
|
#include "panasonic_heatpump.h"
|
||||||
|
#include "esphome/core/application.h"
|
||||||
|
|
||||||
|
|
||||||
namespace esphome
|
namespace esphome
|
||||||
|
|
@ -10,41 +11,110 @@ namespace esphome
|
||||||
void PanasonicHeatpumpComponent::dump_config()
|
void PanasonicHeatpumpComponent::dump_config()
|
||||||
{
|
{
|
||||||
ESP_LOGCONFIG(TAG, "Panasonic Heatpump");
|
ESP_LOGCONFIG(TAG, "Panasonic Heatpump");
|
||||||
delay(10);
|
delay(10); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::setup()
|
void PanasonicHeatpumpComponent::setup()
|
||||||
{
|
{
|
||||||
ESP_LOGCONFIG(TAG, "Setting up Panasonic Heatpump ...");
|
ESP_LOGCONFIG(TAG, "Setting up Panasonic Heatpump ...");
|
||||||
delay(10);
|
delay(10); // NOLINT
|
||||||
this->check_uart_settings(9600, 1, uart::UART_CONFIG_PARITY_EVEN, 8);
|
this->check_uart_settings(9600, 1, uart::UART_CONFIG_PARITY_EVEN, 8);
|
||||||
// Trigger initial request
|
this->update();
|
||||||
if (this->uart_client_ == nullptr)
|
|
||||||
{
|
|
||||||
this->next_request_ = 0;
|
|
||||||
this->trigger_request_ = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->trigger_request_ = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::update()
|
void PanasonicHeatpumpComponent::update()
|
||||||
{
|
{
|
||||||
if (this->uart_client_ == nullptr)
|
if (this->uart_client_ == nullptr)
|
||||||
this->trigger_request_ = true;
|
this->next_request_ = RequestType::POLLING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::loop()
|
void PanasonicHeatpumpComponent::loop()
|
||||||
{
|
{
|
||||||
this->read_response();
|
switch (this->loop_state_)
|
||||||
this->send_request();
|
{
|
||||||
this->read_request();
|
case LoopState::READ_RESPONSE:
|
||||||
|
{
|
||||||
|
this->read_response();
|
||||||
|
this->loop_state_ = LoopState::CHECK_RESPONSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::CHECK_RESPONSE:
|
||||||
|
{
|
||||||
|
bool result = this->check_response(this->heatpump_message_);
|
||||||
|
this->loop_state_ = result ?
|
||||||
|
LoopState::SET_NUMBER_TRAITS : LoopState::SEND_REQUEST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::SET_NUMBER_TRAITS:
|
||||||
|
{
|
||||||
|
this->set_number_traits(this->heatpump_message_);
|
||||||
|
this->loop_state_ = LoopState::PUBLISH_SENSOR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::PUBLISH_SENSOR:
|
||||||
|
{
|
||||||
|
this->publish_sensor(this->heatpump_message_);
|
||||||
|
this->loop_state_ = LoopState::PUBLISH_BINARY_SENSOR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::PUBLISH_BINARY_SENSOR:
|
||||||
|
{
|
||||||
|
this->publish_binary_sensor(this->heatpump_message_);
|
||||||
|
this->loop_state_ = LoopState::PUBLISH_TEXT_SENSOR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::PUBLISH_TEXT_SENSOR:
|
||||||
|
{
|
||||||
|
this->publish_text_sensor(this->heatpump_message_);
|
||||||
|
this->loop_state_ = LoopState::PUBLISH_NUMBER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::PUBLISH_NUMBER:
|
||||||
|
{
|
||||||
|
this->publish_number(this->heatpump_message_);
|
||||||
|
this->loop_state_ = LoopState::PUBLISH_SELECT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::PUBLISH_SELECT:
|
||||||
|
{
|
||||||
|
this->publish_select(this->heatpump_message_);
|
||||||
|
this->loop_state_ = LoopState::PUBLISH_SWITCH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::PUBLISH_SWITCH:
|
||||||
|
{
|
||||||
|
this->publish_switch(this->heatpump_message_);
|
||||||
|
this->loop_state_ = LoopState::SEND_REQUEST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::SEND_REQUEST:
|
||||||
|
{
|
||||||
|
this->send_request(this->next_request_);
|
||||||
|
this->loop_state_ = LoopState::READ_REQUEST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LoopState::READ_REQUEST:
|
||||||
|
{
|
||||||
|
this->read_request();
|
||||||
|
this->loop_state_ = LoopState::RESTART_LOOP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Perform reboot only if a traits (e.g. min/max value of a number entity) was changed the second time.
|
||||||
|
// The first traits change should happen before controller is connected to home assistant,
|
||||||
|
// because the default min/max value is 0.
|
||||||
|
if (this->trait_update_counter_ > 1)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Min/max values have changed. Rebooting so Home Assistant reconfigures the number component.");
|
||||||
|
delay(100); // NOLINT
|
||||||
|
App.safe_reboot();
|
||||||
|
}
|
||||||
|
|
||||||
// Next request will be polling
|
this->loop_state_ = LoopState::READ_RESPONSE;
|
||||||
this->next_request_ = 1;
|
break;
|
||||||
this->trigger_request_ = false;
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::read_response()
|
void PanasonicHeatpumpComponent::read_response()
|
||||||
|
|
@ -71,7 +141,7 @@ namespace esphome
|
||||||
// 2. byte contains the payload size
|
// 2. byte contains the payload size
|
||||||
if (this->response_message_.size() == 2)
|
if (this->response_message_.size() == 2)
|
||||||
{
|
{
|
||||||
this->response_payload_length_ = byte_;
|
this->payload_length_ = byte_;
|
||||||
}
|
}
|
||||||
// Discard message if format is wrong
|
// Discard message if format is wrong
|
||||||
if ((this->response_message_.size() == 3 ||
|
if ((this->response_message_.size() == 3 ||
|
||||||
|
|
@ -81,49 +151,51 @@ namespace esphome
|
||||||
this->response_receiving_ = false;
|
this->response_receiving_ = false;
|
||||||
ESP_LOGW(TAG, "Invalid response message: %d. byte is 0x%02X but expexted is 0x01 or 0x10",
|
ESP_LOGW(TAG, "Invalid response message: %d. byte is 0x%02X but expexted is 0x01 or 0x10",
|
||||||
response_message_.size(), byte_);
|
response_message_.size(), byte_);
|
||||||
delay(10);
|
delay(10); // NOLINT
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if message is complete
|
// Check if message is complete
|
||||||
if (this->response_message_.size() > 2 &&
|
if (this->response_message_.size() > 2 &&
|
||||||
this->response_message_.size() == this->response_payload_length_ + 3)
|
this->response_message_.size() == this->payload_length_ + 3)
|
||||||
{
|
{
|
||||||
this->temp_message_ = this->response_message_;
|
this->heatpump_message_ = this->response_message_;
|
||||||
this->response_receiving_ = false;
|
this->response_receiving_ = false;
|
||||||
this->log_uart_hex(UART_LOG_RX, this->response_message_, ',');
|
this->current_response_count_++;
|
||||||
this->decode_response(this->response_message_);;
|
if (this->log_uart_msg_) PanasonicHelpers::log_uart_hex(UART_LOG_RX, this->response_message_, ',');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::send_request()
|
void PanasonicHeatpumpComponent::send_request(RequestType requestType)
|
||||||
{
|
{
|
||||||
if (this->trigger_request_ == false) return;
|
switch (requestType)
|
||||||
|
|
||||||
if (this->next_request_ == 2) // command
|
|
||||||
{
|
{
|
||||||
this->log_uart_hex(UART_LOG_TX, this->command_message_, ',');
|
case RequestType::COMMAND:
|
||||||
this->write_array(this->command_message_);
|
{
|
||||||
this->flush();
|
if (this->log_uart_msg_) PanasonicHelpers::log_uart_hex(UART_LOG_TX, this->command_message_, ',');
|
||||||
return;
|
this->write_array(this->command_message_);
|
||||||
}
|
this->flush();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RequestType::INITIAL:
|
||||||
|
{
|
||||||
|
// Probably not necessary but CZ-TAW1 sends this query on boot
|
||||||
|
if (this->log_uart_msg_) PanasonicHelpers::log_uart_hex(UART_LOG_TX, PanasonicCommand::InitialRequest, INIT_REQUEST_SIZE, ',');
|
||||||
|
this->write_array(PanasonicCommand::InitialRequest, INIT_REQUEST_SIZE);
|
||||||
|
this->flush();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RequestType::POLLING:
|
||||||
|
{
|
||||||
|
if (this->log_uart_msg_) PanasonicHelpers::log_uart_hex(UART_LOG_TX, PanasonicCommand::PollingMessage, DATA_MESSAGE_SIZE, ',');
|
||||||
|
this->write_array(PanasonicCommand::PollingMessage, DATA_MESSAGE_SIZE);
|
||||||
|
this->flush();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (this->uart_client_ != nullptr) return;
|
this->next_request_ = RequestType::NONE;
|
||||||
|
|
||||||
if (this->next_request_ == 0) // initial
|
|
||||||
{
|
|
||||||
// Probably not necessary but CZ-TAW1 sends this query on boot
|
|
||||||
this->log_uart_hex(UART_LOG_TX, PanasonicCommand::InitialRequest, INIT_REQUEST_SIZE, ',');
|
|
||||||
this->write_array(PanasonicCommand::InitialRequest, INIT_REQUEST_SIZE);
|
|
||||||
this->flush();
|
|
||||||
}
|
|
||||||
else if (this->next_request_ == 1) // polling
|
|
||||||
{
|
|
||||||
this->log_uart_hex(UART_LOG_TX, PanasonicCommand::PollingMessage, DATA_MESSAGE_SIZE, ',');
|
|
||||||
this->write_array(PanasonicCommand::PollingMessage, DATA_MESSAGE_SIZE);
|
|
||||||
this->flush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::read_request()
|
void PanasonicHeatpumpComponent::read_request()
|
||||||
|
|
@ -149,7 +221,7 @@ namespace esphome
|
||||||
// 2. byte contains the payload size
|
// 2. byte contains the payload size
|
||||||
if (this->request_message_.size() == 2)
|
if (this->request_message_.size() == 2)
|
||||||
{
|
{
|
||||||
this->request_payload_length_ = byte_;
|
this->payload_length_ = byte_;
|
||||||
}
|
}
|
||||||
// Discard message if format is wrong
|
// Discard message if format is wrong
|
||||||
if ((this->request_message_.size() == 3 ||
|
if ((this->request_message_.size() == 3 ||
|
||||||
|
|
@ -159,82 +231,41 @@ namespace esphome
|
||||||
this->request_receiving_ = false;
|
this->request_receiving_ = false;
|
||||||
ESP_LOGW(TAG, "Invalid request message: %d. byte is 0x%02X but expexted is 0x01 or 0x10",
|
ESP_LOGW(TAG, "Invalid request message: %d. byte is 0x%02X but expexted is 0x01 or 0x10",
|
||||||
request_message_.size(), byte_);
|
request_message_.size(), byte_);
|
||||||
delay(10);
|
delay(10); // NOLINT
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if message is complete
|
// Check if message is complete
|
||||||
if (this->request_message_.size() > 2 &&
|
if (this->request_message_.size() > 2 &&
|
||||||
this->request_message_.size() == this->request_payload_length_ + 3)
|
this->request_message_.size() == this->payload_length_ + 3)
|
||||||
{
|
{
|
||||||
this->request_receiving_ = false;
|
this->request_receiving_ = false;
|
||||||
this->log_uart_hex(UART_LOG_TX, this->request_message_, ',');
|
if (this->log_uart_msg_) PanasonicHelpers::log_uart_hex(UART_LOG_TX, this->request_message_, ',');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int PanasonicHeatpumpComponent::getResponseByte(const int index)
|
int PanasonicHeatpumpComponent::getResponseByte(const int index)
|
||||||
{
|
{
|
||||||
|
if (this->heatpump_message_.size() > index) return this->heatpump_message_[index];
|
||||||
if (this->response_message_.size() > index) return this->response_message_[index];
|
if (this->response_message_.size() > index) return this->response_message_[index];
|
||||||
if (this->temp_message_.size() > index) return this->temp_message_[index];
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::log_uart_hex(UartLogDirection direction, const std::vector<uint8_t>& data, const char separator)
|
bool PanasonicHeatpumpComponent::check_response(const std::vector<uint8_t>& data)
|
||||||
{
|
|
||||||
this->log_uart_hex(direction, &data[0], data.size(), separator);
|
|
||||||
}
|
|
||||||
void PanasonicHeatpumpComponent::log_uart_hex(UartLogDirection direction, const uint8_t* data, const size_t length, const char separator)
|
|
||||||
{
|
|
||||||
if (this->log_uart_msg_ == false) return;
|
|
||||||
|
|
||||||
std::string logStr = "";
|
|
||||||
std::string msgDir = direction == UART_LOG_TX ? ">>>" : "<<<";
|
|
||||||
std::string msgType = direction == UART_LOG_TX ? "request" : "response";
|
|
||||||
switch(data[0])
|
|
||||||
{
|
|
||||||
case 0x31:
|
|
||||||
msgType = "initial_" + msgType;
|
|
||||||
break;
|
|
||||||
case 0x71:
|
|
||||||
msgType = "polling_" + msgType;
|
|
||||||
break;
|
|
||||||
case 0xF1:
|
|
||||||
msgType = "command_" + msgType;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "%s %s[%i]", msgDir.c_str(), msgType.c_str(), length);
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
char buffer[5];
|
|
||||||
for (size_t i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
if (i > 0) logStr += separator;
|
|
||||||
sprintf(buffer, "%02X", data[i]);
|
|
||||||
logStr += buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < logStr.length(); i += UART_LOG_CHUNK_SIZE)
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "%s %s", msgDir.c_str(), logStr.substr(i, UART_LOG_CHUNK_SIZE).c_str());
|
|
||||||
delay(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::decode_response(const std::vector<uint8_t>& data)
|
|
||||||
{
|
{
|
||||||
// Read response message:
|
// Read response message:
|
||||||
// format: 0x71 [payload_length] 0x01 0x10 [[TOP0 - TOP114] ...] 0x00 [checksum]
|
// format: 0x71 [payload_length] 0x01 0x10 [[TOP0 - TOP114] ...] 0x00 [checksum]
|
||||||
// payload_length: payload_length + 3 = packet_length
|
// payload_length: payload_length + 3 = packet_length
|
||||||
// checksum: if (sum(all bytes) & 0xFF == 0) ==> valid packet
|
// checksum: if (sum(all bytes) & 0xFF == 0) ==> valid packet
|
||||||
|
|
||||||
if (data[0] != 0x71) return;
|
if (data.empty()) return false;
|
||||||
|
if (data[0] != 0x71) return false;
|
||||||
if (data.size() != RESPONSE_MSG_SIZE)
|
if (data.size() != RESPONSE_MSG_SIZE)
|
||||||
{
|
{
|
||||||
ESP_LOGW(TAG, "Invalid response message length: recieved %d - expected %d", data.size(), RESPONSE_MSG_SIZE);
|
ESP_LOGW(TAG, "Invalid response message length: recieved %d - expected %d", data.size(), RESPONSE_MSG_SIZE);
|
||||||
delay(10);
|
delay(10); // NOLINT
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t checksum = 0;
|
uint8_t checksum = 0;
|
||||||
|
|
@ -246,21 +277,18 @@ namespace esphome
|
||||||
if (checksum != 0)
|
if (checksum != 0)
|
||||||
{
|
{
|
||||||
ESP_LOGW(TAG, "Invalid response message: checksum = 0x%02X, last_byte = 0x%02X", checksum, data[202]);
|
ESP_LOGW(TAG, "Invalid response message: checksum = 0x%02X, last_byte = 0x%02X", checksum, data[202]);
|
||||||
delay(10);
|
delay(10); // NOLINT
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->publish_sensor(data);
|
if (this->last_response_count_ == this->current_response_count_) return false;
|
||||||
this->publish_binary_sensor(data);
|
this->last_response_count_ = this->current_response_count_;
|
||||||
this->publish_text_sensor(data);
|
return true;
|
||||||
this->publish_number(data);
|
|
||||||
this->publish_select(data);
|
|
||||||
this->publish_switch(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::set_command_byte(const uint8_t value, const uint8_t index)
|
void PanasonicHeatpumpComponent::set_command_byte(const uint8_t value, const uint8_t index)
|
||||||
{
|
{
|
||||||
if (this->next_request_ == 1)
|
if (this->next_request_ != RequestType::COMMAND)
|
||||||
{
|
{
|
||||||
// initialize the command
|
// initialize the command
|
||||||
command_message_.assign(std::begin(PanasonicCommand::CommandMessage),
|
command_message_.assign(std::begin(PanasonicCommand::CommandMessage),
|
||||||
|
|
@ -272,13 +300,12 @@ namespace esphome
|
||||||
command_message_.back() = PanasonicCommand::calcChecksum(command_message_, command_message_.size() - 1);
|
command_message_.back() = PanasonicCommand::calcChecksum(command_message_, command_message_.size() - 1);
|
||||||
|
|
||||||
// command will be send on next loop
|
// command will be send on next loop
|
||||||
this->next_request_ = 2;
|
this->next_request_ = RequestType::COMMAND;
|
||||||
this->trigger_request_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::set_command_bytes(const std::vector<std::tuple<uint8_t, uint8_t>>& data)
|
void PanasonicHeatpumpComponent::set_command_bytes(const std::vector<std::tuple<uint8_t, uint8_t>>& data)
|
||||||
{
|
{
|
||||||
if (this->next_request_ == 1)
|
if (this->next_request_ != RequestType::COMMAND)
|
||||||
{
|
{
|
||||||
// initialize the command
|
// initialize the command
|
||||||
command_message_.assign(std::begin(PanasonicCommand::CommandMessage),
|
command_message_.assign(std::begin(PanasonicCommand::CommandMessage),
|
||||||
|
|
@ -295,13 +322,91 @@ namespace esphome
|
||||||
command_message_.back() = PanasonicCommand::calcChecksum(command_message_, command_message_.size() - 1);
|
command_message_.back() = PanasonicCommand::calcChecksum(command_message_, command_message_.size() - 1);
|
||||||
|
|
||||||
// command will be send on next loop
|
// command will be send on next loop
|
||||||
this->next_request_ = 2;
|
this->next_request_ = RequestType::COMMAND;
|
||||||
this->trigger_request_ = true;
|
}
|
||||||
|
|
||||||
|
void PanasonicHeatpumpComponent::set_number_traits(const std::vector<uint8_t>& data)
|
||||||
|
{
|
||||||
|
#ifdef USE_TEXT_SENSOR
|
||||||
|
#ifdef USE_NUMBER
|
||||||
|
if (data.empty()) return;
|
||||||
|
|
||||||
|
// traits can be changed anytime, but entities will only be updated in home assistant,
|
||||||
|
// if the traits was set before connecting to home assistant. If now a traits must be changed later,
|
||||||
|
// a reboot of the ESP controller is required to see the changes in home assistant.
|
||||||
|
|
||||||
|
bool change_detected = false;
|
||||||
|
std::string top76 = PanasonicDecode::getTextState(
|
||||||
|
PanasonicDecode::HeatCoolModeDesc, PanasonicDecode::getBit7and8(data[28])); // Heating Mode
|
||||||
|
std::string top81 = PanasonicDecode::getTextState(
|
||||||
|
PanasonicDecode::HeatCoolModeDesc, PanasonicDecode::getBit5and6(data[28])); // Cooling Mode
|
||||||
|
float set5_min = this->set5_number_->traits.get_min_value(); // Z1 Heat Request Temperature
|
||||||
|
float set6_min = this->set6_number_->traits.get_min_value(); // Z1 Cool Request Temperature
|
||||||
|
float set7_min = this->set7_number_->traits.get_min_value(); // Z2 Heat Request Temperature
|
||||||
|
float set8_min = this->set8_number_->traits.get_min_value(); // Z2 Cool Request Temperature
|
||||||
|
|
||||||
|
if (set5_min >= 0.0 && top76 == PanasonicDecode::HeatCoolModeDesc[1])
|
||||||
|
{
|
||||||
|
this->set5_number_->traits.set_min_value(-5.0);
|
||||||
|
this->set5_number_->traits.set_max_value(5.0);
|
||||||
|
change_detected = true;
|
||||||
|
}
|
||||||
|
if (set6_min >= 0.0 && top81 == PanasonicDecode::HeatCoolModeDesc[1])
|
||||||
|
{
|
||||||
|
this->set6_number_->traits.set_min_value(-5.0);
|
||||||
|
this->set6_number_->traits.set_max_value(5.0);
|
||||||
|
change_detected = true;
|
||||||
|
}
|
||||||
|
if (set7_min >= 0.0 && top76 == PanasonicDecode::HeatCoolModeDesc[1])
|
||||||
|
{
|
||||||
|
this->set7_number_->traits.set_min_value(-5.0);
|
||||||
|
this->set7_number_->traits.set_max_value(5.0);
|
||||||
|
change_detected = true;
|
||||||
|
}
|
||||||
|
if (set8_min >= 0.0 && top81 == PanasonicDecode::HeatCoolModeDesc[1])
|
||||||
|
{
|
||||||
|
this->set8_number_->traits.set_min_value(-5.0);
|
||||||
|
this->set8_number_->traits.set_max_value(5.0);
|
||||||
|
change_detected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set5_min <= 0.0 && top76 == PanasonicDecode::HeatCoolModeDesc[2])
|
||||||
|
{
|
||||||
|
this->set5_number_->traits.set_min_value(20.0);
|
||||||
|
this->set5_number_->traits.set_max_value(60.0);
|
||||||
|
change_detected = true;
|
||||||
|
}
|
||||||
|
if (set6_min <= 0.0 && top81 == PanasonicDecode::HeatCoolModeDesc[2])
|
||||||
|
{
|
||||||
|
this->set6_number_->traits.set_min_value(20.0);
|
||||||
|
this->set6_number_->traits.set_max_value(60.0);
|
||||||
|
change_detected = true;
|
||||||
|
}
|
||||||
|
if (set7_min <= 0.0 && top76 == PanasonicDecode::HeatCoolModeDesc[2])
|
||||||
|
{
|
||||||
|
this->set7_number_->traits.set_min_value(20.0);
|
||||||
|
this->set7_number_->traits.set_max_value(60.0);
|
||||||
|
change_detected = true;
|
||||||
|
}
|
||||||
|
if (set8_min <= 0.0 && top81 == PanasonicDecode::HeatCoolModeDesc[2])
|
||||||
|
{
|
||||||
|
this->set8_number_->traits.set_min_value(20.0);
|
||||||
|
this->set8_number_->traits.set_max_value(60.0);
|
||||||
|
change_detected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change_detected)
|
||||||
|
{
|
||||||
|
this->trait_update_counter_++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::publish_sensor(const std::vector<uint8_t>& data)
|
void PanasonicHeatpumpComponent::publish_sensor(const std::vector<uint8_t>& data)
|
||||||
{
|
{
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
|
if (data.empty()) return;
|
||||||
if (this->top1_sensor_) this->top1_sensor_->publish_state(PanasonicDecode::getPumpFlow(data[169], data[170]));
|
if (this->top1_sensor_) this->top1_sensor_->publish_state(PanasonicDecode::getPumpFlow(data[169], data[170]));
|
||||||
if (this->top5_sensor_) this->top5_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[143]) + PanasonicDecode::getFractional(data[118], 0));
|
if (this->top5_sensor_) this->top5_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[143]) + PanasonicDecode::getFractional(data[118], 0));
|
||||||
if (this->top6_sensor_) this->top6_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[144]) + PanasonicDecode::getFractional(data[118], 3));
|
if (this->top6_sensor_) this->top6_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[144]) + PanasonicDecode::getFractional(data[118], 3));
|
||||||
|
|
@ -403,6 +508,7 @@ namespace esphome
|
||||||
void PanasonicHeatpumpComponent::publish_binary_sensor(const std::vector<uint8_t>& data)
|
void PanasonicHeatpumpComponent::publish_binary_sensor(const std::vector<uint8_t>& data)
|
||||||
{
|
{
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
if (data.empty()) return;
|
||||||
if (this->top0_binary_sensor_) this->top0_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[4])));
|
if (this->top0_binary_sensor_) this->top0_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[4])));
|
||||||
if (this->top2_binary_sensor_) this->top2_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[4])));
|
if (this->top2_binary_sensor_) this->top2_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[4])));
|
||||||
if (this->top3_binary_sensor_) this->top3_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[7])));
|
if (this->top3_binary_sensor_) this->top3_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[7])));
|
||||||
|
|
@ -432,6 +538,7 @@ namespace esphome
|
||||||
void PanasonicHeatpumpComponent::publish_text_sensor(const std::vector<uint8_t>& data)
|
void PanasonicHeatpumpComponent::publish_text_sensor(const std::vector<uint8_t>& data)
|
||||||
{
|
{
|
||||||
#ifdef USE_TEXT_SENSOR
|
#ifdef USE_TEXT_SENSOR
|
||||||
|
if (data.empty()) return;
|
||||||
if (this->top4_text_sensor_) this->top4_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::OpModeDesc, PanasonicDecode::getOpMode(data[6])));
|
if (this->top4_text_sensor_) this->top4_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::OpModeDesc, PanasonicDecode::getOpMode(data[6])));
|
||||||
if (this->top17_text_sensor_) this->top17_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Powerfulmode, PanasonicDecode::getBit6and7and8(data[7])));
|
if (this->top17_text_sensor_) this->top17_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Powerfulmode, PanasonicDecode::getBit6and7and8(data[7])));
|
||||||
if (this->top18_text_sensor_) this->top18_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Quietmode, PanasonicDecode::getBit3and4and5(data[7])));
|
if (this->top18_text_sensor_) this->top18_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Quietmode, PanasonicDecode::getBit3and4and5(data[7])));
|
||||||
|
|
@ -459,6 +566,7 @@ namespace esphome
|
||||||
void PanasonicHeatpumpComponent::publish_number(const std::vector<uint8_t>& data)
|
void PanasonicHeatpumpComponent::publish_number(const std::vector<uint8_t>& data)
|
||||||
{
|
{
|
||||||
#ifdef USE_NUMBER
|
#ifdef USE_NUMBER
|
||||||
|
if (data.empty()) return;
|
||||||
if (this->set11_number_) this->set11_number_->publish_state(PanasonicDecode::getByteMinus128(data[42]));
|
if (this->set11_number_) this->set11_number_->publish_state(PanasonicDecode::getByteMinus128(data[42]));
|
||||||
if (this->set20_number_) this->set20_number_->publish_state(PanasonicDecode::getByteMinus128(data[99]));
|
if (this->set20_number_) this->set20_number_->publish_state(PanasonicDecode::getByteMinus128(data[99]));
|
||||||
if (this->set18_number_) this->set18_number_->publish_state(PanasonicDecode::getByteMinus128(data[84]));
|
if (this->set18_number_) this->set18_number_->publish_state(PanasonicDecode::getByteMinus128(data[84]));
|
||||||
|
|
@ -498,6 +606,7 @@ namespace esphome
|
||||||
void PanasonicHeatpumpComponent::publish_select(const std::vector<uint8_t>& data)
|
void PanasonicHeatpumpComponent::publish_select(const std::vector<uint8_t>& data)
|
||||||
{
|
{
|
||||||
#ifdef USE_SELECT
|
#ifdef USE_SELECT
|
||||||
|
if (data.empty()) return;
|
||||||
if (this->set9_select_) this->set9_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::OpModeDesc, PanasonicDecode::getOpMode(data[6])));
|
if (this->set9_select_) this->set9_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::OpModeDesc, PanasonicDecode::getOpMode(data[6])));
|
||||||
if (this->set4_select_) this->set4_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Powerfulmode, PanasonicDecode::getBit6and7and8(data[7])));
|
if (this->set4_select_) this->set4_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Powerfulmode, PanasonicDecode::getBit6and7and8(data[7])));
|
||||||
if (this->set3_select_) this->set3_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Quietmode, PanasonicDecode::getBit3and4and5(data[7])));
|
if (this->set3_select_) this->set3_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Quietmode, PanasonicDecode::getBit3and4and5(data[7])));
|
||||||
|
|
@ -510,7 +619,8 @@ namespace esphome
|
||||||
|
|
||||||
void PanasonicHeatpumpComponent::publish_switch(const std::vector<uint8_t>& data)
|
void PanasonicHeatpumpComponent::publish_switch(const std::vector<uint8_t>& data)
|
||||||
{
|
{
|
||||||
#ifdef USE_SWITCH
|
#ifdef USE_SWITCH
|
||||||
|
if (data.empty()) return;
|
||||||
if (this->set1_switch_) this->set1_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[4])));
|
if (this->set1_switch_) this->set1_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[4])));
|
||||||
if (this->set10_switch_) this->set10_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[4])));
|
if (this->set10_switch_) this->set10_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[4])));
|
||||||
if (this->set24_switch_) this->set24_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[5])));
|
if (this->set24_switch_) this->set24_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[5])));
|
||||||
|
|
|
||||||
|
|
@ -24,21 +24,38 @@
|
||||||
#endif
|
#endif
|
||||||
#include "decode.h"
|
#include "decode.h"
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
|
#include "helpers.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#define UART_LOG_CHUNK_SIZE 153
|
|
||||||
|
|
||||||
|
|
||||||
namespace esphome
|
namespace esphome
|
||||||
{
|
{
|
||||||
namespace panasonic_heatpump
|
namespace panasonic_heatpump
|
||||||
{
|
{
|
||||||
enum UartLogDirection
|
enum LoopState
|
||||||
{
|
{
|
||||||
UART_LOG_RX,
|
READ_RESPONSE,
|
||||||
UART_LOG_TX,
|
CHECK_RESPONSE,
|
||||||
|
SET_NUMBER_TRAITS,
|
||||||
|
PUBLISH_SENSOR,
|
||||||
|
PUBLISH_BINARY_SENSOR,
|
||||||
|
PUBLISH_TEXT_SENSOR,
|
||||||
|
PUBLISH_NUMBER,
|
||||||
|
PUBLISH_SELECT,
|
||||||
|
PUBLISH_SWITCH,
|
||||||
|
SEND_REQUEST,
|
||||||
|
READ_REQUEST,
|
||||||
|
RESTART_LOOP
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RequestType
|
||||||
|
{
|
||||||
|
INITIAL,
|
||||||
|
POLLING,
|
||||||
|
COMMAND,
|
||||||
|
NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
class PanasonicHeatpumpComponent : public PollingComponent, public uart::UARTDevice
|
class PanasonicHeatpumpComponent : public PollingComponent, public uart::UARTDevice
|
||||||
|
|
@ -258,7 +275,7 @@ namespace esphome
|
||||||
|
|
||||||
PanasonicHeatpumpComponent() = default;
|
PanasonicHeatpumpComponent() = default;
|
||||||
// base class functions
|
// base class functions
|
||||||
float get_setup_priority() const override { return setup_priority::LATE; }
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void update() override;
|
void update() override;
|
||||||
|
|
@ -274,35 +291,35 @@ namespace esphome
|
||||||
uart::UARTComponent* uart_client_ { nullptr };
|
uart::UARTComponent* uart_client_ { nullptr };
|
||||||
bool log_uart_msg_ { false };
|
bool log_uart_msg_ { false };
|
||||||
// uart message variables
|
// uart message variables
|
||||||
std::vector<uint8_t> temp_message_;
|
std::vector<uint8_t> heatpump_message_;
|
||||||
std::vector<uint8_t> response_message_;
|
std::vector<uint8_t> response_message_;
|
||||||
std::vector<uint8_t> request_message_;
|
std::vector<uint8_t> request_message_;
|
||||||
std::vector<uint8_t> command_message_;
|
std::vector<uint8_t> command_message_;
|
||||||
uint8_t response_payload_length_;
|
uint8_t payload_length_;
|
||||||
uint8_t request_payload_length_;
|
|
||||||
uint8_t byte_;
|
uint8_t byte_;
|
||||||
|
uint8_t current_response_count_ { 0 };
|
||||||
|
uint8_t last_response_count_ { 0 };
|
||||||
bool response_receiving_ { false };
|
bool response_receiving_ { false };
|
||||||
bool request_receiving_ { false };
|
bool request_receiving_ { false };
|
||||||
bool trigger_request_ { false };
|
RequestType next_request_ { RequestType::INITIAL };
|
||||||
uint8_t next_request_ { 0 }; // 0 = initial, 1 = polling, 2 = command
|
LoopState loop_state_ { LoopState::RESTART_LOOP };
|
||||||
|
uint16_t trait_update_counter_ { 0 };
|
||||||
|
|
||||||
// uart message functions
|
// uart message functions
|
||||||
void read_response();
|
void read_response();
|
||||||
void send_request();
|
void send_request(RequestType requestType);
|
||||||
void read_request();
|
void read_request();
|
||||||
void decode_response(const std::vector<uint8_t>& data);
|
bool check_response(const std::vector<uint8_t>& data);
|
||||||
void set_command_byte(const uint8_t value, const uint8_t index);
|
void set_command_byte(const uint8_t value, const uint8_t index);
|
||||||
void set_command_bytes(const std::vector<std::tuple<uint8_t, uint8_t>>& data);
|
void set_command_bytes(const std::vector<std::tuple<uint8_t, uint8_t>>& data);
|
||||||
// sensor and control publish functions
|
// sensor and control publish functions
|
||||||
|
void set_number_traits(const std::vector<uint8_t>& data);
|
||||||
void publish_sensor(const std::vector<uint8_t>& data);
|
void publish_sensor(const std::vector<uint8_t>& data);
|
||||||
void publish_binary_sensor(const std::vector<uint8_t>& data);
|
void publish_binary_sensor(const std::vector<uint8_t>& data);
|
||||||
void publish_text_sensor(const std::vector<uint8_t>& data);
|
void publish_text_sensor(const std::vector<uint8_t>& data);
|
||||||
void publish_number(const std::vector<uint8_t>& data);
|
void publish_number(const std::vector<uint8_t>& data);
|
||||||
void publish_select(const std::vector<uint8_t>& data);
|
void publish_select(const std::vector<uint8_t>& data);
|
||||||
void publish_switch(const std::vector<uint8_t>& data);
|
void publish_switch(const std::vector<uint8_t>& data);
|
||||||
// helper functions
|
|
||||||
void log_uart_hex(UartLogDirection direction, const std::vector<uint8_t>& data, const char separator);
|
|
||||||
void log_uart_hex(UartLogDirection direction, const uint8_t* data, const size_t length, const char separator);
|
|
||||||
};
|
};
|
||||||
} // namespace panasonic_heatpump
|
} // namespace panasonic_heatpump
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ CONF_SET2 = "set2" # Set Holiday Mode
|
||||||
CONF_SET3 = "set3" # Set Quiet Mode
|
CONF_SET3 = "set3" # Set Quiet Mode
|
||||||
CONF_SET4 = "set4" # Set Powerful Mode
|
CONF_SET4 = "set4" # Set Powerful Mode
|
||||||
CONF_SET9 = "set9" # Set Operation Mode
|
CONF_SET9 = "set9" # Set Operation Mode
|
||||||
|
# ToDo: Split up set9 into set9_1 (Heating Mode) and set9_2 (DHW Mode)
|
||||||
CONF_SET17 = "set17" # Set Zones
|
CONF_SET17 = "set17" # Set Zones
|
||||||
CONF_SET26 = "set26" # Set External PadHeater
|
CONF_SET26 = "set26" # Set External PadHeater
|
||||||
CONF_SET35 = "set35" # Set Bivalent Mode
|
CONF_SET35 = "set35" # Set Bivalent Mode
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ ICON_EXTERNAL_PAD_HEATER = "mdi:radiator"
|
||||||
|
|
||||||
|
|
||||||
CONF_TOP4 = "top4" # Operating Mode State
|
CONF_TOP4 = "top4" # Operating Mode State
|
||||||
|
# ToDo: Split up top4 into top4_1 (Heating Mode State) and top4_2 (DHW Mode State)
|
||||||
CONF_TOP17 = "top17" # Powerful Mode Time
|
CONF_TOP17 = "top17" # Powerful Mode Time
|
||||||
CONF_TOP18 = "top18" # Quiet Mode Level
|
CONF_TOP18 = "top18" # Quiet Mode Level
|
||||||
CONF_TOP19 = "top19" # Holiday Mode State
|
CONF_TOP19 = "top19" # Holiday Mode State
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue