From 37ed1ff63cec55997b63dae66839bab69b2ffee9 Mon Sep 17 00:00:00 2001
From: Miika Pekkarinen <miipekk@ihme.org>
Date: Sun, 6 Oct 2024 09:51:25 +0300
Subject: [PATCH] Add support for compressor frequency in 16-bit format with 1
 decimal.

---
 components/cn105/Globals.h       |  6 +++---
 components/cn105/cn105.cpp       |  9 ++++----
 components/cn105/cn105.h         |  4 ++--
 components/cn105/hp_readings.cpp | 36 ++++++++++++++++++++------------
 components/cn105/hp_writings.cpp |  8 +++----
 components/cn105/utils.cpp       |  6 +++---
 6 files changed, 39 insertions(+), 30 deletions(-)

diff --git a/components/cn105/Globals.h b/components/cn105/Globals.h
index 85687aa..3354139 100644
--- a/components/cn105/Globals.h
+++ b/components/cn105/Globals.h
@@ -189,7 +189,7 @@ struct wantedHeatpumpSettings : heatpumpSettings {
         hasChanged = false;
         hasBeenSent = false;
         //nb_deffered_requests = 0;
-        //lastChange = 0; 
+        //lastChange = 0;
     }
 
     wantedHeatpumpSettings& operator=(const wantedHeatpumpSettings& other) {
@@ -203,7 +203,7 @@ struct wantedHeatpumpSettings : heatpumpSettings {
 
     wantedHeatpumpSettings& operator=(const heatpumpSettings& other) {
         if (this != &other) { // self-assignment protection
-            heatpumpSettings::operator=(other); // Copie des membres de base                        
+            heatpumpSettings::operator=(other); // Copie des membres de base
         }
         return *this;
     }
@@ -246,7 +246,7 @@ struct heatpumpStatus {
     float roomTemperature;
     bool operating; // if true, the heatpump is operating to reach the desired temperature
     heatpumpTimers timers;
-    int compressorFrequency;
+    float compressorFrequency;
 
     bool operator==(const heatpumpStatus& other) const {
         return roomTemperature == other.roomTemperature &&
diff --git a/components/cn105/cn105.cpp b/components/cn105/cn105.cpp
index 638f5c6..ba6acb4 100644
--- a/components/cn105/cn105.cpp
+++ b/components/cn105/cn105.cpp
@@ -36,7 +36,7 @@ CN105Climate::CN105Climate(uart::UARTComponent* uart) :
 
     this->powerRequestWithoutResponses = 0;     // power request is not supported by all heatpump #112
 
-    this->remote_temp_timeout_ = 4294967295;    // uint32_t max    
+    this->remote_temp_timeout_ = 4294967295;    // uint32_t max
     this->generateExtraComponents();
     this->loopCycle.init();
     this->wantedSettings.resetSettings();
@@ -71,7 +71,7 @@ void CN105Climate::set_remote_temp_timeout(uint32_t timeout) {
     if (timeout == 4294967295) {
         ESP_LOGI(LOG_ACTION_EVT_TAG, "set_remote_temp_timeout is set to never.");
     } else {
-        //ESP_LOGI(LOG_ACTION_EVT_TAG, "set_remote_temp_timeout is set to %lu", timeout);        
+        //ESP_LOGI(LOG_ACTION_EVT_TAG, "set_remote_temp_timeout is set to %lu", timeout);
         log_info_uint32(LOG_ACTION_EVT_TAG, "set_remote_temp_timeout is set to ", timeout);
 
         this->pingExternalTemperature();
@@ -84,7 +84,7 @@ void CN105Climate::set_debounce_delay(uint32_t delay) {
     log_info_uint32(LOG_ACTION_EVT_TAG, "set_debounce_delay is set to ", delay);
 }
 
-int CN105Climate::get_compressor_frequency() {
+float CN105Climate::get_compressor_frequency() {
     return currentStatus.compressorFrequency;
 }
 bool CN105Climate::is_operating() {
@@ -173,9 +173,8 @@ bool CN105Climate::isHeatpumpConnectionActive() {
     // if (lrTimeMs > MAX_DELAY_RESPONSE_FACTOR * this->update_interval_) {
     //     ESP_LOGV(TAG, "Heatpump has not replied for %ld s", lrTimeMs / 1000);
     //     ESP_LOGV(TAG, "We think Heatpump is not connected anymore..");
-    //     this->disconnectUART();        
+    //     this->disconnectUART();
     // }
 
     return  (lrTimeMs < MAX_DELAY_RESPONSE_FACTOR * this->update_interval_);
 }
-
diff --git a/components/cn105/cn105.h b/components/cn105/cn105.h
index 9ba37ea..c57b243 100644
--- a/components/cn105/cn105.h
+++ b/components/cn105/cn105.h
@@ -55,10 +55,10 @@ class CN105Climate : public climate::Climate, public Component, public uart::UAR
     sensor::Sensor* compressor_frequency_sensor_ =
         nullptr;  // Sensor to store compressor frequency
 
-    // sensor to monitor heatpump connection time 
+    // sensor to monitor heatpump connection time
     uptime::HpUpTimeConnectionSensor* hp_uptime_connection_sensor_ = nullptr;
 
-    int get_compressor_frequency();
+    float get_compressor_frequency();
     bool is_operating();
 
     // checks if the field has changed
diff --git a/components/cn105/hp_readings.cpp b/components/cn105/hp_readings.cpp
index 5d47a1e..e904163 100644
--- a/components/cn105/hp_readings.cpp
+++ b/components/cn105/hp_readings.cpp
@@ -118,7 +118,7 @@ void CN105Climate::processDataPacket() {
 
     if (this->checkSum()) {
         // checkPoint of a heatpump response
-        this->lastResponseMs = CUSTOM_MILLIS;    //esphome::CUSTOM_MILLIS;        
+        this->lastResponseMs = CUSTOM_MILLIS;    //esphome::CUSTOM_MILLIS;
 
         // processing the specific command
         processCommand();
@@ -172,7 +172,7 @@ void CN105Climate::getSettingsFromResponsePacket() {
     heatpumpSettings receivedSettings{};
     ESP_LOGD("Decoder", "[0x02 is settings]");
     //02 00 00 01 08 0A 00 07 00 00 03 AA 00 00 00 00 94
-    //this->last_received_packet_sensor->publish_state("0x62-> 0x02: Data -> Settings");        
+    //this->last_received_packet_sensor->publish_state("0x62-> 0x02: Data -> Settings");
     receivedSettings.connected = true;      // we're here so we're connected (actually not used property)
     receivedSettings.power = lookupByteMapValue(POWER_MAP, POWER, 2, data[3], "power reading");
     receivedSettings.iSee = data[4] > 0x08 ? true : false;
@@ -227,7 +227,7 @@ void CN105Climate::getRoomTemperatureFromResponsePacket() {
     heatpumpStatus receivedStatus{};
 
     //ESP_LOGD("Decoder", "[0x03 room temperature]");
-    //this->last_received_packet_sensor->publish_state("0x62-> 0x03: Data -> Room temperature");        
+    //this->last_received_packet_sensor->publish_state("0x62-> 0x03: Data -> Room temperature");
 
     if (data[6] != 0x00) {
         int temp = data[6];
@@ -246,6 +246,14 @@ void CN105Climate::getRoomTemperatureFromResponsePacket() {
 }
 void CN105Climate::getOperatingAndCompressorFreqFromResponsePacket() {
     //FC 62 01 30 10 06 00 00 1A 01 00 00 00 00 00 00 00 00 00 00 00 3C
+    //MSZ-RW25VGHZ-SC1 / MUZ-RW25VGHZ-SC1
+    //FC 62 01 30 10 06 00 00 00 01 00 08 05 50 00 00 42 00 00 00 00 B7
+    //                           OP CF CF ?? CT       ??
+    // OP = operating status (1 = compressor running, 0 = standby)
+    // CF = compressor frequency in 16-bit integer, 1 decimal accuracy
+    //      (frequency in float = value / 10)
+    // CT = slowly increasing counter, unknown function
+    // ?? = unknown bytes that appear to have a fixed/constant value
     heatpumpStatus receivedStatus{};
     ESP_LOGD("Decoder", "[0x06 is status]");
     //this->last_received_packet_sensor->publish_state("0x62-> 0x06: Data -> Heatpump Status");
@@ -253,7 +261,10 @@ void CN105Climate::getOperatingAndCompressorFreqFromResponsePacket() {
     // reset counter (because a reply indicates it is connected)
     this->nonResponseCounter = 0;
     receivedStatus.operating = data[4];
-    receivedStatus.compressorFrequency = data[3];
+    if (data[5] || data[6])
+        receivedStatus.compressorFrequency = (float)((data[5] << 8) | data[6]) / 10;
+    else
+        receivedStatus.compressorFrequency = (float)data[3];
 
     // no change with this packet to roomTemperature
     receivedStatus.roomTemperature = currentStatus.roomTemperature;
@@ -281,7 +292,7 @@ void CN105Climate::getDataFromResponsePacket() {
     case 0x02:             /* setting information */
         ESP_LOGD(LOG_CYCLE_TAG, "2b: Receiving settings response");
         this->getSettingsFromResponsePacket();
-        // next step is to get the room temperature case 0x03        
+        // next step is to get the room temperature case 0x03
         ESP_LOGD(LOG_CYCLE_TAG, "3a: Sending room °C request (0x03)");
         this->buildAndSendRequestPacket(RQST_PKT_ROOM_TEMP);
         break;
@@ -290,7 +301,7 @@ void CN105Climate::getDataFromResponsePacket() {
         /* room temperature reading */
         ESP_LOGD(LOG_CYCLE_TAG, "3b: Receiving room °C response");
         this->getRoomTemperatureFromResponsePacket();
-        // next step is to get the heatpump status (operating and compressor frequency) case 0x06        
+        // next step is to get the heatpump status (operating and compressor frequency) case 0x06
         ESP_LOGD(LOG_CYCLE_TAG, "4a: Sending status request (0x06)");
         this->buildAndSendRequestPacket(RQST_PKT_STATUS);
         break;
@@ -330,7 +341,7 @@ void CN105Climate::getDataFromResponsePacket() {
         /* Power */
         ESP_LOGD(LOG_CYCLE_TAG, "5b: Receiving Power/Standby response");
         this->getPowerFromResponsePacket();
-        //FC 62 01 30 10 09 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 50                     
+        //FC 62 01 30 10 09 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 50
         // reset the powerRequestWithoutResponses to 0 as we had a response
         this->powerRequestWithoutResponses = 0;
 
@@ -386,9 +397,9 @@ void CN105Climate::processCommand() {
         ESP_LOGI(TAG, "--> Heatpump did reply: connection success! <--");
         //this->isHeatpumpConnected_ = true;
         this->setHeatpumpConnected(true);
-        // let's say that the last complete cycle was over now        
+        // let's say that the last complete cycle was over now
         this->loopCycle.lastCompleteCycleMs = CUSTOM_MILLIS;
-        this->currentSettings.resetSettings();      // each time we connect, we need to reset current setting to force a complete sync with ha component state and receievdSettings 
+        this->currentSettings.resetSettings();      // each time we connect, we need to reset current setting to force a complete sync with ha component state and receievdSettings
         break;
     default:
         break;
@@ -408,7 +419,7 @@ void CN105Climate::statusChanged(heatpumpStatus status) {
         this->currentStatus.roomTemperature = status.roomTemperature;
         this->current_temperature = currentStatus.roomTemperature;
 
-        this->updateAction();       // update action info on HA climate component        
+        this->updateAction();       // update action info on HA climate component
         this->publish_state();
 
         if (this->compressor_frequency_sensor_ != nullptr) {
@@ -420,7 +431,7 @@ void CN105Climate::statusChanged(heatpumpStatus status) {
 
 void CN105Climate::publishStateToHA(heatpumpSettings settings) {
 
-    if ((this->wantedSettings.mode == nullptr) && (this->wantedSettings.power == nullptr)) {        // to prevent overwriting a user demand 
+    if ((this->wantedSettings.mode == nullptr) && (this->wantedSettings.power == nullptr)) {        // to prevent overwriting a user demand
         checkPowerAndModeSettings(settings);
     }
 
@@ -454,7 +465,7 @@ void CN105Climate::publishStateToHA(heatpumpSettings settings) {
 
 
 void CN105Climate::heatpumpUpdate(heatpumpSettings settings) {
-    // settings correponds to current settings 
+    // settings correponds to current settings
     ESP_LOGV(LOG_SETTINGS_TAG, "Settings received");
 
     this->debugSettings("current", this->currentSettings);
@@ -622,4 +633,3 @@ void CN105Climate::checkPowerAndModeSettings(heatpumpSettings& settings, bool up
         }
     }
 }
-
diff --git a/components/cn105/hp_writings.cpp b/components/cn105/hp_writings.cpp
index 3db8404..808da38 100644
--- a/components/cn105/hp_writings.cpp
+++ b/components/cn105/hp_writings.cpp
@@ -51,7 +51,7 @@ void CN105Climate::sendFirstConnectionPacket() {
 
 //     ESP_LOGD(TAG, "t°: %f", currentStatus.roomTemperature);
 //     ESP_LOGD(TAG, "operating: %d", currentStatus.operating);
-//     ESP_LOGD(TAG, "compressor freq: %d", currentStatus.compressorFrequency);
+//     ESP_LOGD(TAG, "compressor freq: %f", currentStatus.compressorFrequency);
 
 //     this->updateAction();
 //     this->publish_state();
@@ -275,10 +275,10 @@ void CN105Climate::sendWantedSettings() {
 #ifdef USE_ESP32
             std::lock_guard<std::mutex> guard(wantedSettingsMutex);
             this->sendWantedSettingsDelegate();
-#else            
+#else
             this->emulateMutex("WRITE_SETTINGS", std::bind(&CN105Climate::sendWantedSettingsDelegate, this));
 
-#endif                
+#endif
 
         } else {
             ESP_LOGD(TAG, "will sendWantedSettings later because we've sent one too recently...");
@@ -379,4 +379,4 @@ void CN105Climate::sendRemoteTemperature() {
     this->pingExternalTemperature();
 
 
-}
\ No newline at end of file
+}
diff --git a/components/cn105/utils.cpp b/components/cn105/utils.cpp
index 5803f55..e611305 100644
--- a/components/cn105/utils.cpp
+++ b/components/cn105/utils.cpp
@@ -125,13 +125,13 @@ void CN105Climate::debugSettings(const char* settingName, heatpumpSettings setti
 
 void CN105Climate::debugStatus(const char* statusName, heatpumpStatus status) {
 #ifdef USE_ESP32
-    ESP_LOGI(LOG_STATUS_TAG, "[%s]-> [room C°: %.1f, operating: %s, compressor freq: %2d Hz]",
+    ESP_LOGI(LOG_STATUS_TAG, "[%s]-> [room C°: %.1f, operating: %s, compressor freq: %.1f Hz]",
         statusName,
         status.roomTemperature,
         status.operating ? "YES" : "NO ",
         status.compressorFrequency);
 #else
-    ESP_LOGI(LOG_STATUS_TAG, "[%-*s]-> [room C°: %.1f, operating: %-*s, compressor freq: %2d Hz]",
+    ESP_LOGI(LOG_STATUS_TAG, "[%-*s]-> [room C°: %.1f, operating: %-*s, compressor freq: %.1f Hz]",
         15, statusName,
         status.roomTemperature,
         3, status.operating ? "YES" : "NO ",
@@ -280,7 +280,7 @@ void CN105Climate::logDelegate() {
     } else {
         ESP_LOGI("testMutex", "Mutex est déjà verrouillé");
     }
-#endif    
+#endif
 }
 
 void CN105Climate::testCase1() {