Skip to content

Commit

Permalink
Merge pull request #88 from jmichiel/cnt_buffering
Browse files Browse the repository at this point in the history
Simple Command buffering for CN-CNT
  • Loading branch information
DomiStyle authored Jun 21, 2023
2 parents d2a7481 + f3d2fb0 commit ad692ac
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 52 deletions.
138 changes: 86 additions & 52 deletions components/panasonic_ac/esppac_cnt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void PanasonicACCNT::loop() {

this->rx_buffer_.clear(); // Reset buffer
}

handle_cmd();
handle_poll(); // Handle sending poll packets
}

Expand All @@ -43,27 +43,32 @@ void PanasonicACCNT::control(const climate::ClimateCall &call) {
if (this->state_ != ACState::Ready)
return;

if (this->cmd.empty()) {
ESP_LOGV(TAG, "Copying data to cmd");
this->cmd = this->data;
}

if (call.get_mode().has_value()) {
ESP_LOGV(TAG, "Requested mode change");

switch (*call.get_mode()) {
case climate::CLIMATE_MODE_COOL:
this->data[0] = 0x34;
this->cmd[0] = 0x34;
break;
case climate::CLIMATE_MODE_HEAT:
this->data[0] = 0x44;
this->cmd[0] = 0x44;
break;
case climate::CLIMATE_MODE_DRY:
this->data[0] = 0x24;
this->cmd[0] = 0x24;
break;
case climate::CLIMATE_MODE_HEAT_COOL:
this->data[0] = 0x04;
this->cmd[0] = 0x04;
break;
case climate::CLIMATE_MODE_FAN_ONLY:
this->data[0] = 0x64;
this->cmd[0] = 0x64;
break;
case climate::CLIMATE_MODE_OFF:
this->data[0] = this->data[0] & 0xF0; // Strip right nib to turn AC off
this->cmd[0] = this->cmd[0] & 0xF0; // Strip right nib to turn AC off
break;
default:
ESP_LOGV(TAG, "Unsupported mode requested");
Expand All @@ -72,7 +77,7 @@ void PanasonicACCNT::control(const climate::ClimateCall &call) {
}

if (call.get_target_temperature().has_value()) {
this->data[1] = *call.get_target_temperature() / TEMPERATURE_STEP;
this->cmd[1] = *call.get_target_temperature() / TEMPERATURE_STEP;
}

if (call.get_custom_fan_mode().has_value()) {
Expand All @@ -81,23 +86,23 @@ void PanasonicACCNT::control(const climate::ClimateCall &call) {
if(this->custom_preset != "Normal")
{
ESP_LOGV(TAG, "Resetting preset");
this->data[5] = (this->data[5] & 0xF0); // Clear right nib for normal mode
this->cmd[5] = (this->cmd[5] & 0xF0); // Clear right nib for normal mode
}

std::string fanMode = *call.get_custom_fan_mode();

if (fanMode == "Automatic")
this->data[3] = 0xA0;
this->cmd[3] = 0xA0;
else if (fanMode == "1")
this->data[3] = 0x30;
this->cmd[3] = 0x30;
else if (fanMode == "2")
this->data[3] = 0x40;
this->cmd[3] = 0x40;
else if (fanMode == "3")
this->data[3] = 0x50;
this->cmd[3] = 0x50;
else if (fanMode == "4")
this->data[3] = 0x60;
this->cmd[3] = 0x60;
else if (fanMode == "5")
this->data[3] = 0x70;
this->cmd[3] = 0x70;
else
ESP_LOGV(TAG, "Unsupported fan mode requested");
}
Expand All @@ -107,16 +112,16 @@ void PanasonicACCNT::control(const climate::ClimateCall &call) {

switch (*call.get_swing_mode()) {
case climate::CLIMATE_SWING_BOTH:
this->data[4] = 0xFD;
this->cmd[4] = 0xFD;
break;
case climate::CLIMATE_SWING_OFF:
this->data[4] = 0x36; // Reset both to center
this->cmd[4] = 0x36; // Reset both to center
break;
case climate::CLIMATE_SWING_VERTICAL:
this->data[4] = 0xF6; // Swing vertical, horizontal center
this->cmd[4] = 0xF6; // Swing vertical, horizontal center
break;
case climate::CLIMATE_SWING_HORIZONTAL:
this->data[4] = 0x3D; // Swing horizontal, vertical center
this->cmd[4] = 0x3D; // Swing horizontal, vertical center
break;
default:
ESP_LOGV(TAG, "Unsupported swing mode requested");
Expand All @@ -130,16 +135,15 @@ void PanasonicACCNT::control(const climate::ClimateCall &call) {
std::string preset = *call.get_custom_preset();

if (preset.compare("Normal") == 0)
this->data[5] = (this->data[5] & 0xF0); // Clear right nib for normal mode
this->cmd[5] = (this->cmd[5] & 0xF0); // Clear right nib for normal mode
else if (preset.compare("Powerful") == 0)
this->data[5] = (this->data[5] & 0xF0) + 0x02; // Clear right nib and set powerful mode
this->cmd[5] = (this->cmd[5] & 0xF0) + 0x02; // Clear right nib and set powerful mode
else if (preset.compare("Quiet") == 0)
this->data[5] = (this->data[5] & 0xF0) + 0x04; // Clear right nib and set quiet mode
this->cmd[5] = (this->cmd[5] & 0xF0) + 0x04; // Clear right nib and set quiet mode
else
ESP_LOGV(TAG, "Unsupported preset requested");
}

send_command(this->data, CommandType::Normal, CTRL_HEADER);
}

/*
Expand Down Expand Up @@ -250,6 +254,14 @@ void PanasonicACCNT::handle_poll() {
}
}

void PanasonicACCNT::handle_cmd() {
if (!this->cmd.empty() && millis() - this->last_packet_sent_ > CMD_INTERVAL) {
ESP_LOGV(TAG, "Sending Command");
send_command(this->cmd, CommandType::Normal, CTRL_HEADER);
this->cmd.clear();
}
}

/*
* Packet handling
*/
Expand Down Expand Up @@ -480,26 +492,30 @@ void PanasonicACCNT::on_vertical_swing_change(const std::string &swing) {

ESP_LOGD(TAG, "Setting vertical swing position");

if (this->cmd.empty()) {
ESP_LOGV(TAG, "Copying data to cmd");
this->cmd = this->data;
}

if (swing == "down")
this->data[4] = (this->data[4] & 0x0F) + 0x50;
this->cmd[4] = (this->cmd[4] & 0x0F) + 0x50;
else if (swing == "down_center")
this->data[4] = (this->data[4] & 0x0F) + 0x40;
this->cmd[4] = (this->cmd[4] & 0x0F) + 0x40;
else if (swing == "center")
this->data[4] = (this->data[4] & 0x0F) + 0x30;
this->cmd[4] = (this->cmd[4] & 0x0F) + 0x30;
else if (swing == "up_center")
this->data[4] = (this->data[4] & 0x0F) + 0x20;
this->cmd[4] = (this->cmd[4] & 0x0F) + 0x20;
else if (swing == "up")
this->data[4] = (this->data[4] & 0x0F) + 0x10;
this->cmd[4] = (this->cmd[4] & 0x0F) + 0x10;
else if (swing == "swing")
this->data[4] = (this->data[4] & 0x0F) + 0xE0;
this->cmd[4] = (this->cmd[4] & 0x0F) + 0xE0;
else if (swing == "auto")
this->data[4] = (this->data[4] & 0x0F) + 0xF0;
this->cmd[4] = (this->cmd[4] & 0x0F) + 0xF0;
else {
ESP_LOGW(TAG, "Unsupported vertical swing position received");
return;
}

send_command(this->data, CommandType::Normal, CTRL_HEADER);
}

void PanasonicACCNT::on_horizontal_swing_change(const std::string &swing) {
Expand All @@ -508,92 +524,110 @@ void PanasonicACCNT::on_horizontal_swing_change(const std::string &swing) {

ESP_LOGD(TAG, "Setting horizontal swing position");

if (this->cmd.empty()) {
ESP_LOGV(TAG, "Copying data to cmd");
this->cmd = this->data;
}

if (swing == "left")
this->data[4] = (this->data[4] & 0xF0) + 0x09;
this->cmd[4] = (this->cmd[4] & 0xF0) + 0x09;
else if (swing == "left_center")
this->data[4] = (this->data[4] & 0xF0) + 0x0A;
this->cmd[4] = (this->cmd[4] & 0xF0) + 0x0A;
else if (swing == "center")
this->data[4] = (this->data[4] & 0xF0) + 0x06;
this->cmd[4] = (this->cmd[4] & 0xF0) + 0x06;
else if (swing == "right_center")
this->data[4] = (this->data[4] & 0xF0) + 0x0B;
this->cmd[4] = (this->cmd[4] & 0xF0) + 0x0B;
else if (swing == "right")
this->data[4] = (this->data[4] & 0xF0) + 0x0C;
this->cmd[4] = (this->cmd[4] & 0xF0) + 0x0C;
else if (swing == "auto")
this->data[4] = (this->data[4] & 0xF0) + 0x0D;
this->cmd[4] = (this->cmd[4] & 0xF0) + 0x0D;
else {
ESP_LOGW(TAG, "Unsupported horizontal swing position received");
return;
}

send_command(this->data, CommandType::Normal, CTRL_HEADER);
}

void PanasonicACCNT::on_nanoex_change(bool state) {
if (this->state_ != ACState::Ready)
return;

if (this->cmd.empty()) {
ESP_LOGV(TAG, "Copying data to cmd");
this->cmd = this->data;
}

this->nanoex_state_ = state;

if (state) {
ESP_LOGV(TAG, "Turning nanoex on");
this->data[5] = (this->data[5] & 0x0F) + 0x40;
this->cmd[5] = (this->cmd[5] & 0x0F) + 0x40;
} else {
ESP_LOGV(TAG, "Turning nanoex off");
this->data[5] = (this->data[5] & 0x0F);
this->cmd[5] = (this->cmd[5] & 0x0F);
}

send_command(this->data, CommandType::Normal, CTRL_HEADER);
}

void PanasonicACCNT::on_eco_change(bool state) {
if (this->state_ != ACState::Ready)
return;

if (this->cmd.empty()) {
ESP_LOGV(TAG, "Copying data to cmd");
this->cmd = this->data;
}

this->eco_state_ = state;

if (state) {
ESP_LOGV(TAG, "Turning eco mode on");
this->data[8] = 0x40;
this->cmd[8] = 0x40;
} else {
ESP_LOGV(TAG, "Turning eco mode off");
this->data[8] = 0x00;
this->cmd[8] = 0x00;
}

send_command(this->data, CommandType::Normal, CTRL_HEADER);
}

void PanasonicACCNT::on_econavi_change(bool state) {
if (this->state_ != ACState::Ready)
return;

if (this->cmd.empty()) {
ESP_LOGV(TAG, "Copying data to cmd");
this->cmd = this->data;
}

this->econavi_state_ = state;

if (state) {
ESP_LOGV(TAG, "Turning econavi mode on");
this->data[5] = 0x10;
this->cmd[5] = 0x10;
} else {
ESP_LOGV(TAG, "Turning econavi mode off");
this->data[5] = 0x00;
this->cmd[5] = 0x00;
}

send_command(this->data, CommandType::Normal, CTRL_HEADER);
}

void PanasonicACCNT::on_mild_dry_change(bool state) {
if (this->state_ != ACState::Ready)
return;

if (this->cmd.empty()) {
ESP_LOGV(TAG, "Copying data to cmd");
this->cmd = this->data;
}

this->mild_dry_state_ = state;

if (state) {
ESP_LOGV(TAG, "Turning mild dry on");
this->data[2] = 0x7F;
this->cmd[2] = 0x7F;
} else {
ESP_LOGV(TAG, "Turning mild dry off");
this->data[2] = 0x80;
this->cmd[2] = 0x80;
}

send_command(this->data, CommandType::Normal, CTRL_HEADER);
}

} // namespace CNT
Expand Down
4 changes: 4 additions & 0 deletions components/panasonic_ac/esppac_cnt.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ static const uint8_t CTRL_HEADER = 0xF0; // The header for control frames
static const uint8_t POLL_HEADER = 0x70; // The header for the poll command

static const int POLL_INTERVAL = 5000; // The interval at which to poll the AC
static const int CMD_INTERVAL = 250; // The interval at which to send commands

enum class ACState {
Initializing, // Before first query response is receive
Expand All @@ -35,7 +36,10 @@ class PanasonicACCNT : public PanasonicAC {

// uint8_t data[10];
std::vector<uint8_t> data = std::vector<uint8_t>(10); // Stores the data received from the AC
std::vector<uint8_t> cmd; // Used to build next command

void handle_poll();
void handle_cmd();

void set_data(bool set);

Expand Down

0 comments on commit ad692ac

Please sign in to comment.