Added support for extra query (fixes #11)
This commit is contained in:
parent
505d643bf0
commit
3753b3d475
|
|
@ -24,6 +24,16 @@ namespace esphome
|
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x12
|
||||
};
|
||||
const uint8_t PanasonicCommand::PollingExtraMessage[DATA_MESSAGE_SIZE] = {
|
||||
0x71, 0x6C, 0x01, 0x21, 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, 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,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
const uint8_t PanasonicCommand::CommandMessage[DATA_MESSAGE_SIZE] = {
|
||||
0xF1, 0x6C, 0x01, 0x10, 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,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ namespace esphome
|
|||
static const uint8_t InitialRequest[INIT_REQUEST_SIZE];
|
||||
static const uint8_t InitialResponse[INIT_RESPONSE_SIZE];
|
||||
static const uint8_t PollingMessage[DATA_MESSAGE_SIZE];
|
||||
static const uint8_t PollingExtraMessage[DATA_MESSAGE_SIZE];
|
||||
static const uint8_t CommandMessage[DATA_MESSAGE_SIZE];
|
||||
};
|
||||
} // namespace panasonic_heatpump
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ namespace esphome
|
|||
|
||||
void PanasonicHeatpumpComponent::update()
|
||||
{
|
||||
if (this->uart_client_ == nullptr)
|
||||
this->next_request_ = RequestType::POLLING;
|
||||
if (this->uart_client_ != nullptr) return;
|
||||
this->next_request_ = this->send_extra_request_ ? RequestType::POLLING_EXTRA : RequestType::POLLING;
|
||||
}
|
||||
|
||||
void PanasonicHeatpumpComponent::loop()
|
||||
|
|
@ -34,98 +34,91 @@ namespace esphome
|
|||
switch (this->loop_state_)
|
||||
{
|
||||
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::PUBLISH_SENSOR : LoopState::SEND_REQUEST;
|
||||
this->current_response_ = this->check_response(this->heatpump_message_);
|
||||
switch (this->current_response_)
|
||||
{
|
||||
case ResponseType::UNKNOWN:
|
||||
this->loop_state_ = LoopState::SEND_REQUEST;
|
||||
break;
|
||||
case ResponseType::DEFAULT:
|
||||
this->loop_state_ = LoopState::PUBLISH_SENSOR;
|
||||
break;
|
||||
case ResponseType::EXTRA:
|
||||
this->loop_state_ = LoopState::PUBLISH_EXTRA_SENSOR;
|
||||
break;
|
||||
};
|
||||
break;
|
||||
}
|
||||
case LoopState::PUBLISH_SENSOR:
|
||||
{
|
||||
for (auto *entity : this->sensors_)
|
||||
{
|
||||
entity->publish_new_state(this->heatpump_message_);
|
||||
}
|
||||
this->loop_state_ = LoopState::PUBLISH_BINARY_SENSOR;
|
||||
break;
|
||||
}
|
||||
case LoopState::PUBLISH_BINARY_SENSOR:
|
||||
{
|
||||
for (auto *entity : this->binary_sensors_)
|
||||
{
|
||||
entity->publish_new_state(this->heatpump_message_);
|
||||
}
|
||||
this->loop_state_ = LoopState::PUBLISH_TEXT_SENSOR;
|
||||
break;
|
||||
}
|
||||
case LoopState::PUBLISH_TEXT_SENSOR:
|
||||
{
|
||||
for (auto *entity : this->text_sensors_)
|
||||
{
|
||||
entity->publish_new_state(this->heatpump_message_);
|
||||
}
|
||||
this->loop_state_ = LoopState::PUBLISH_NUMBER;
|
||||
break;
|
||||
}
|
||||
case LoopState::PUBLISH_NUMBER:
|
||||
{
|
||||
for (auto *entity : this->numbers_)
|
||||
{
|
||||
entity->publish_new_state(this->heatpump_message_);
|
||||
}
|
||||
this->loop_state_ = LoopState::PUBLISH_SELECT;
|
||||
break;
|
||||
}
|
||||
case LoopState::PUBLISH_SELECT:
|
||||
{
|
||||
for (auto *entity : this->selects_)
|
||||
{
|
||||
entity->publish_new_state(this->heatpump_message_);
|
||||
}
|
||||
this->loop_state_ = LoopState::PUBLISH_SWITCH;
|
||||
break;
|
||||
}
|
||||
case LoopState::PUBLISH_SWITCH:
|
||||
{
|
||||
for (auto *entity : this->switches_)
|
||||
{
|
||||
entity->publish_new_state(this->heatpump_message_);
|
||||
}
|
||||
this->loop_state_ = LoopState::PUBLISH_CLIMATE;
|
||||
break;
|
||||
}
|
||||
case LoopState::PUBLISH_CLIMATE:
|
||||
{
|
||||
for (auto *entity : this->climates_)
|
||||
{
|
||||
entity->publish_new_state(this->heatpump_message_);
|
||||
}
|
||||
this->loop_state_ = LoopState::SEND_REQUEST;
|
||||
break;
|
||||
}
|
||||
case LoopState::PUBLISH_EXTRA_SENSOR:
|
||||
for (auto *entity : this->extra_sensors_)
|
||||
{
|
||||
entity->publish_new_state(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:
|
||||
{
|
||||
this->loop_state_ = LoopState::READ_RESPONSE;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -205,6 +198,13 @@ namespace esphome
|
|||
this->flush();
|
||||
break;
|
||||
}
|
||||
case RequestType::POLLING_EXTRA:
|
||||
{
|
||||
if (this->log_uart_msg_) PanasonicHelpers::log_uart_hex(UART_LOG_TX, PanasonicCommand::PollingExtraMessage, DATA_MESSAGE_SIZE, ',');
|
||||
this->write_array(PanasonicCommand::PollingMessage, DATA_MESSAGE_SIZE);
|
||||
this->flush();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
this->next_request_ = RequestType::NONE;
|
||||
|
|
@ -264,41 +264,62 @@ namespace esphome
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool PanasonicHeatpumpComponent::check_response(const std::vector<uint8_t>& data)
|
||||
ResponseType PanasonicHeatpumpComponent::check_response(const std::vector<uint8_t>& data)
|
||||
{
|
||||
// Read response message:
|
||||
// format: 0x71 [payload_length] 0x01 0x10 [[TOP0 - TOP114] ...] 0x00 [checksum]
|
||||
// format: 0x71 [payload_length] 0x01 [0x10 || 0x21] [[TOP0 - TOP114] ...] 0x00 [checksum]
|
||||
// payload_length: payload_length + 3 = packet_length
|
||||
// checksum: if (sum(all bytes) & 0xFF == 0) ==> valid packet
|
||||
|
||||
if (data.empty()) return false;
|
||||
if (data[0] != 0x71) return false;
|
||||
if (data[3] != 0x10) return false;
|
||||
if (data.empty()) return ResponseType::UNKNOWN;
|
||||
if (data[0] != 0x71) return ResponseType::UNKNOWN;
|
||||
if (data.size() != RESPONSE_MSG_SIZE)
|
||||
{
|
||||
ESP_LOGW(TAG, "Invalid response message length: recieved %d - expected %d", data.size(), RESPONSE_MSG_SIZE);
|
||||
delay(10); // NOLINT
|
||||
return false;
|
||||
return ResponseType::UNKNOWN;
|
||||
}
|
||||
|
||||
// Verify checksum
|
||||
uint8_t checksum = 0;
|
||||
for (int i = 0; i < data.size(); i++)
|
||||
{
|
||||
checksum += data[i];
|
||||
}
|
||||
// checksum = checksum & 0xFF;
|
||||
// all bytes (including checksum byte) shall be 0x00
|
||||
if (checksum != 0)
|
||||
{
|
||||
ESP_LOGW(TAG, "Invalid response message: checksum = 0x%02X, last_byte = 0x%02X", checksum, data[202]);
|
||||
delay(10); // NOLINT
|
||||
return false;
|
||||
return ResponseType::UNKNOWN;
|
||||
}
|
||||
|
||||
// Get response type
|
||||
auto responseType = ResponseType::UNKNOWN;
|
||||
if (data[3] == 0x10) responseType = ResponseType::DEFAULT;
|
||||
if (data[3] == 0x21) responseType = ResponseType::EXTRA;
|
||||
if (responseType == ResponseType::UNKNOWN)
|
||||
{
|
||||
ESP_LOGW(TAG, "Unknown response type (4. byte): 0x%02X. Expected 0x10 or 0x21.", data[3]);
|
||||
delay(10); // NOLINT
|
||||
return ResponseType::UNKNOWN;
|
||||
}
|
||||
|
||||
// Check if extra request shall be send
|
||||
if (responseType == ResponseType::DEFAULT)
|
||||
{
|
||||
this->send_extra_request_ = data[199] > 0x02 ? true : false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->send_extra_request_ = false;
|
||||
}
|
||||
|
||||
// Check if the current response is a new response
|
||||
if (this->last_response_count_ == this->current_response_count_) return false;
|
||||
if (this->last_response_count_ == this->current_response_count_) return ResponseType::UNKNOWN;
|
||||
this->last_response_count_ = this->current_response_count_;
|
||||
|
||||
return true;
|
||||
return responseType;
|
||||
}
|
||||
|
||||
void PanasonicHeatpumpComponent::set_command_high_nibble(const uint8_t value, const uint8_t index)
|
||||
|
|
|
|||
|
|
@ -27,17 +27,26 @@ namespace esphome
|
|||
PUBLISH_SELECT,
|
||||
PUBLISH_SWITCH,
|
||||
PUBLISH_CLIMATE,
|
||||
PUBLISH_EXTRA_SENSOR,
|
||||
SEND_REQUEST,
|
||||
READ_REQUEST,
|
||||
RESTART_LOOP
|
||||
RESTART_LOOP,
|
||||
};
|
||||
|
||||
enum RequestType : uint8_t
|
||||
{
|
||||
NONE,
|
||||
COMMAND,
|
||||
INITIAL,
|
||||
POLLING,
|
||||
COMMAND,
|
||||
NONE
|
||||
POLLING_EXTRA,
|
||||
};
|
||||
|
||||
enum ResponseType : uint8_t
|
||||
{
|
||||
UNKNOWN,
|
||||
DEFAULT,
|
||||
EXTRA,
|
||||
};
|
||||
|
||||
class PanasonicHeatpumpEntity
|
||||
|
|
@ -79,6 +88,7 @@ namespace esphome
|
|||
void add_sensor(PanasonicHeatpumpEntity *sensor) { sensors_.push_back(sensor); }
|
||||
void add_switch(PanasonicHeatpumpEntity *switch_) { switches_.push_back(switch_); }
|
||||
void add_text_sensor(PanasonicHeatpumpEntity *text_sensor) { text_sensors_.push_back(text_sensor); }
|
||||
void add_extra_sensor(PanasonicHeatpumpEntity *sensor) { extra_sensors_.push_back(sensor); }
|
||||
|
||||
protected:
|
||||
// options variables
|
||||
|
|
@ -95,8 +105,10 @@ namespace esphome
|
|||
uint8_t last_response_count_ { 0 };
|
||||
bool response_receiving_ { false };
|
||||
bool request_receiving_ { false };
|
||||
RequestType next_request_ { RequestType::INITIAL };
|
||||
bool send_extra_request_ { false };
|
||||
LoopState loop_state_ { LoopState::RESTART_LOOP };
|
||||
RequestType next_request_ { RequestType::INITIAL };
|
||||
ResponseType current_response_ { ResponseType::UNKNOWN };
|
||||
// entity vectors
|
||||
std::vector<PanasonicHeatpumpEntity *> binary_sensors_;
|
||||
std::vector<PanasonicHeatpumpEntity *> climates_;
|
||||
|
|
@ -105,12 +117,13 @@ namespace esphome
|
|||
std::vector<PanasonicHeatpumpEntity *> sensors_;
|
||||
std::vector<PanasonicHeatpumpEntity *> switches_;
|
||||
std::vector<PanasonicHeatpumpEntity *> text_sensors_;
|
||||
std::vector<PanasonicHeatpumpEntity *> extra_sensors_;
|
||||
|
||||
// uart message functions
|
||||
void read_response();
|
||||
void send_request(RequestType requestType);
|
||||
void read_request();
|
||||
bool check_response(const std::vector<uint8_t>& data);
|
||||
ResponseType check_response(const std::vector<uint8_t>& data);
|
||||
};
|
||||
} // namespace panasonic_heatpump
|
||||
} // namespace esphome
|
||||
|
|
|
|||
|
|
@ -128,6 +128,13 @@ CONF_TOP136 = "top136" # Bivalent Advanced Start Delay
|
|||
CONF_TOP137 = "top137" # Bivalent Advanced Stop Delay
|
||||
CONF_TOP138 = "top138" # Bivalent Advanced DHW Delay
|
||||
|
||||
CONF_XTOP0 = "xtop0" # Heat Power Consumption Extra
|
||||
CONF_XTOP1 = "xtop1" # Cool Power Consumption Extra
|
||||
CONF_XTOP2 = "xtop2" # DHW Power Consumption Extra
|
||||
CONF_XTOP3 = "xtop3" # Heat Power Production Extra
|
||||
CONF_XTOP4 = "xtop4" # Cool Power Production Extra
|
||||
CONF_XTOP5 = "xtop5" # DHW Power Production Extra
|
||||
|
||||
TYPES = [
|
||||
CONF_TOP1,
|
||||
CONF_TOP5,
|
||||
|
|
@ -226,6 +233,15 @@ TYPES = [
|
|||
CONF_TOP138,
|
||||
]
|
||||
|
||||
EXTRA_TYPES = [
|
||||
CONF_XTOP0,
|
||||
CONF_XTOP1,
|
||||
CONF_XTOP2,
|
||||
CONF_XTOP3,
|
||||
CONF_XTOP4,
|
||||
CONF_XTOP5,
|
||||
]
|
||||
|
||||
PanasonicHeatpumpSensor = panasonic_heatpump_ns.class_("PanasonicHeatpumpSensor", sensor.Sensor, cg.Component)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
|
|
@ -894,6 +910,49 @@ CONFIG_SCHEMA = cv.Schema(
|
|||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
unit_of_measurement = UNIT_MINUTE,
|
||||
),
|
||||
|
||||
cv.Optional(CONF_XTOP0): sensor.sensor_schema(
|
||||
PanasonicHeatpumpSensor,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
unit_of_measurement = UNIT_WATT,
|
||||
),
|
||||
cv.Optional(CONF_XTOP1): sensor.sensor_schema(
|
||||
PanasonicHeatpumpSensor,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
unit_of_measurement = UNIT_WATT,
|
||||
),
|
||||
cv.Optional(CONF_XTOP2): sensor.sensor_schema(
|
||||
PanasonicHeatpumpSensor,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
unit_of_measurement = UNIT_WATT,
|
||||
),
|
||||
cv.Optional(CONF_XTOP3): sensor.sensor_schema(
|
||||
PanasonicHeatpumpSensor,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
unit_of_measurement = UNIT_WATT,
|
||||
),
|
||||
cv.Optional(CONF_XTOP4): sensor.sensor_schema(
|
||||
PanasonicHeatpumpSensor,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
unit_of_measurement = UNIT_WATT,
|
||||
),
|
||||
cv.Optional(CONF_XTOP5): sensor.sensor_schema(
|
||||
PanasonicHeatpumpSensor,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
unit_of_measurement = UNIT_WATT,
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
|
@ -906,3 +965,10 @@ async def to_code(config):
|
|||
cg.add(var.set_parent(parent))
|
||||
cg.add(var.set_id(index))
|
||||
cg.add(parent.add_sensor(var))
|
||||
for index, key in enumerate(EXTRA_TYPES):
|
||||
if child_config := config.get(key):
|
||||
var = await sensor.new_sensor(child_config)
|
||||
await cg.register_component(var, child_config)
|
||||
cg.add(var.set_parent(parent))
|
||||
cg.add(var.set_id(index))
|
||||
cg.add(parent.add_extra_sensor(var))
|
||||
|
|
|
|||
|
|
@ -590,6 +590,43 @@ namespace esphome
|
|||
if (this->has_state() && this->get_state() == new_state) return;
|
||||
break;
|
||||
}
|
||||
|
||||
case SensorIds::CONF_XTOP0:
|
||||
{
|
||||
new_state = PanasonicDecode::getWordMinus1(data, 14);
|
||||
if (this->has_state() && this->get_state() == new_state) return;
|
||||
break;
|
||||
}
|
||||
case SensorIds::CONF_XTOP1:
|
||||
{
|
||||
new_state = PanasonicDecode::getWordMinus1(data, 16);
|
||||
if (this->has_state() && this->get_state() == new_state) return;
|
||||
break;
|
||||
}
|
||||
case SensorIds::CONF_XTOP2:
|
||||
{
|
||||
new_state = PanasonicDecode::getWordMinus1(data, 18);
|
||||
if (this->has_state() && this->get_state() == new_state) return;
|
||||
break;
|
||||
}
|
||||
case SensorIds::CONF_XTOP3:
|
||||
{
|
||||
new_state = PanasonicDecode::getWordMinus1(data, 20);
|
||||
if (this->has_state() && this->get_state() == new_state) return;
|
||||
break;
|
||||
}
|
||||
case SensorIds::CONF_XTOP4:
|
||||
{
|
||||
new_state = PanasonicDecode::getWordMinus1(data, 22);
|
||||
if (this->has_state() && this->get_state() == new_state) return;
|
||||
break;
|
||||
}
|
||||
case SensorIds::CONF_XTOP5:
|
||||
{
|
||||
new_state = PanasonicDecode::getWordMinus1(data, 24);
|
||||
if (this->has_state() && this->get_state() == new_state) return;
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,13 @@ namespace esphome
|
|||
CONF_TOP136,
|
||||
CONF_TOP137,
|
||||
CONF_TOP138,
|
||||
|
||||
CONF_XTOP0,
|
||||
CONF_XTOP1,
|
||||
CONF_XTOP2,
|
||||
CONF_XTOP3,
|
||||
CONF_XTOP4,
|
||||
CONF_XTOP5,
|
||||
};
|
||||
|
||||
class PanasonicHeatpumpSensor : public sensor::Sensor, public Component,
|
||||
|
|
|
|||
Loading…
Reference in New Issue