|
| 1 | +# For all configuration options, see the example.yaml file. This file only |
| 2 | +# shows what you can do with an external Bluetooth temperature sensor. |
| 3 | +# |
| 4 | +# Compared to some other projects, this project does not alter the external |
| 5 | +# sensor value. It passes the rounded value (0.25 degrees Celsius precision) to |
| 6 | +# the AC. That means all the trickery has to happen in the yaml file, which |
| 7 | +# this example will show. |
| 8 | +substitutions: |
| 9 | + mhi_device_id: "mhi_ac_example" |
| 10 | + # Unique device ID in HA |
| 11 | + device_id: "ac_example" |
| 12 | + # Unique device name in HA (sensor names will be prefixed by this name) |
| 13 | + device_name: "AC Example" |
| 14 | + external_temperature_sensor_id: atc_temperature |
| 15 | + |
| 16 | +esphome: |
| 17 | + name: ac-example |
| 18 | + platformio_options: |
| 19 | + board_build.flash_mode: dio |
| 20 | + |
| 21 | +external_components: |
| 22 | + - source: components |
| 23 | +# Or, directly refer to the Git repository |
| 24 | +# - source: github://hberntsen/mhi-ac-ctrl-esp32@master |
| 25 | + |
| 26 | +esp32: |
| 27 | + board: esp32-c3-devkitm-1 |
| 28 | + # Run CPU at slower speed to save power |
| 29 | + cpu_frequency: 80MHz |
| 30 | + framework: |
| 31 | + type: esp-idf |
| 32 | + # Add Bluetooth 5 support |
| 33 | + sdkconfig_options: |
| 34 | + CONFIG_BT_BLE_50_FEATURES_SUPPORTED: y |
| 35 | + |
| 36 | +esp32_ble_tracker: |
| 37 | + scan_parameters: |
| 38 | + active: false |
| 39 | + |
| 40 | +MhiAcCtrl: |
| 41 | + id: ${mhi_device_id} |
| 42 | + mosi_pin: GPIO7 |
| 43 | + miso_pin: GPIO2 |
| 44 | + sclk_pin: GPIO6 |
| 45 | + use_long_frame: true |
| 46 | + # Send the value of this temperature sensor to the AC (degrees Celsius) |
| 47 | + external_temperature_sensor: ${device_id}_calculated_external_sensor |
| 48 | + |
| 49 | +climate: |
| 50 | + - platform: MhiAcCtrl |
| 51 | + mhi_ac_ctrl_id: ${mhi_device_id} |
| 52 | + id: ${device_id} |
| 53 | + name: "${device_name}" |
| 54 | + visual: |
| 55 | + temperature_step: |
| 56 | + # Upgrade to 0.5 degrees Celsius, we're adding support for this by |
| 57 | + # manipulating the external sensor in the lambda later below. |
| 58 | + target_temperature: 0.5 |
| 59 | + current_temperature: 0.25 |
| 60 | + on_control: |
| 61 | + - then: |
| 62 | + - lambda: id(${device_id}_calculated_external_sensor).update(); |
| 63 | + |
| 64 | +sensor: |
| 65 | + - platform: MhiAcCtrl |
| 66 | + mhi_ac_ctrl_id: ${mhi_device_id} |
| 67 | + # The current temperature in the climate component will use the filtered |
| 68 | + # value from this sensor. |
| 69 | + # |
| 70 | + # Use case: filtering out internal temperature sensor jitter and overriding |
| 71 | + # climate temperature with external, when available. |
| 72 | + climate_current_temperature: |
| 73 | + # Only id, no name so it won't be sent to home assistant as separate sensor |
| 74 | + id: climate_current_temperature |
| 75 | + accuracy_decimals: 2 |
| 76 | + filters: |
| 77 | + # Override the climate's temperature with our external sensor, if it is |
| 78 | + # available. Otherwise, our manipulated sensor value is shown on the |
| 79 | + # Climate card in Home Assistant. |
| 80 | + - lambda: |- |
| 81 | + float Troom = id(${external_temperature_sensor_id}).state; |
| 82 | + if(!isnan(Troom)) { |
| 83 | + return Troom; |
| 84 | + } |
| 85 | + return x; |
| 86 | + # Check for temperature changes only every 10 seconds |
| 87 | + - heartbeat: 10s |
| 88 | + # The climate component will only send updates if the value is different |
| 89 | + |
| 90 | + # The return_air_temperature sensor will show the external (or internal if |
| 91 | + # the external sensor is unavailable) temperature value we have sent to the |
| 92 | + # AC. |
| 93 | + return_air_temperature: |
| 94 | + name: Return air temperature |
| 95 | + # When the setpoint changes, also update the external sensor's value |
| 96 | + set_temperature: |
| 97 | + name: Set temperature |
| 98 | + id: ${device_id}_set_temperature |
| 99 | + on_value: |
| 100 | + - then: |
| 101 | + - lambda: id(${device_id}_calculated_external_sensor).update(); |
| 102 | + |
| 103 | + # Example: use this Bluetooth sensor as external temperature sensor |
| 104 | + - platform: pvvx_mithermometer |
| 105 | + mac_address: "AA:BB:CC:DD:EE:FF" |
| 106 | + temperature: |
| 107 | + id: atc_temperature |
| 108 | + name: "ATC Temperature" |
| 109 | + filters: |
| 110 | + # Stop using this sensor when it did not update in the last 10 minutes. |
| 111 | + - timeout: 10min |
| 112 | + # Filter out 0 degrees, some bug makes it sometimes send 0. |
| 113 | + - filter_out: 0 |
| 114 | + on_value: |
| 115 | + - then: |
| 116 | + - lambda: id(${device_id}_calculated_external_sensor).update(); |
| 117 | + |
| 118 | + - platform: template |
| 119 | + name: Calculated external sensor |
| 120 | + id: ${device_id}_calculated_external_sensor |
| 121 | + unit_of_measurement: "°C" |
| 122 | + entity_category: diagnostic |
| 123 | + lambda: |- |
| 124 | + float Troom = id(${external_temperature_sensor_id}).state; |
| 125 | + float Tset = id(${device_id}).target_temperature; |
| 126 | +
|
| 127 | + // Use the internal sensor when the external one is not available, or we have no set point |
| 128 | + if (isnan(Troom) || isnan(Tset)) { |
| 129 | + return NAN; |
| 130 | + } |
| 131 | +
|
| 132 | + float TsetInternal = max(18.f, Tset); |
| 133 | + float TsetReported = id(${device_id}_set_temperature).state; |
| 134 | +
|
| 135 | + // The AC internally won't go lower than 18, support lower temperatures through |
| 136 | + // increasing the external temperature |
| 137 | + Troom += TsetInternal - Tset; |
| 138 | +
|
| 139 | + // The AC increases your set point internally. The internal set point is set_temperature in the operation data. |
| 140 | + // Known reasons for increases: |
| 141 | + // * The AC internally adds 2 degrees when heating, unless turned off (excessive heating compensation). |
| 142 | + // * 3D auto heating adds 1 degree |
| 143 | + // |
| 144 | + // We undo these compensations, so it will heat to exactly the set point we want |
| 145 | + if (!isnan(TsetReported)) { |
| 146 | + Troom += TsetReported - TsetInternal; |
| 147 | + } |
| 148 | +
|
| 149 | +
|
| 150 | + /* |
| 151 | + Limit the max temperature delta via a slider. When heating/cooling, the |
| 152 | + AC will see a temperature that is closer to your set point. Some AC |
| 153 | + models will reduce their power when they are made to believe they are |
| 154 | + almost there. Some might ramp up since it takes too long to get there. So |
| 155 | + you need to test with this. You can safely remove this block and the |
| 156 | + slider if you don't want to use this. |
| 157 | + */ |
| 158 | + float TmaxDelta = id(${device_id}_max_temperature_delta).state; |
| 159 | + if (id(${device_id}).mode == climate::CLIMATE_MODE_HEAT) { |
| 160 | + // Heating: clamp downward only (don't suppress a hot room reading) |
| 161 | + Troom = max(Troom, TsetReported - TmaxDelta); |
| 162 | + } else if (id(${device_id}).mode == climate::CLIMATE_MODE_COOL) { |
| 163 | + // Cooling: clamp upward only (don't suppress a cold room reading) |
| 164 | + Troom = min(Troom, TsetReported + TmaxDelta); |
| 165 | + } |
| 166 | +
|
| 167 | + // Use our new calculated value. |
| 168 | + return Troom; |
| 169 | +
|
| 170 | +number: |
| 171 | + # This slider defines the limit of how much degrees Celsius of a difference |
| 172 | + # between the external sensor and the AC's setpoint you want to be sent to |
| 173 | + # the AC. It is used by the calculated external sensor lambda above. |
| 174 | + # |
| 175 | + # For example: |
| 176 | + # * Your external temperature sensor says it is 18 degrees |
| 177 | + # * You set your AC to 20 degrees in heating mode |
| 178 | + # * You set this slider to 10 degrees |
| 179 | + # |
| 180 | + # Then, the AC will see 18 degrees as room temperature, since 20-18 > 10. |
| 181 | + # |
| 182 | + # Suppose you now set this slider to 1.0, the AC will receive 19 degrees room |
| 183 | + # temperature instead of 18. You might be able to use this to reduce power |
| 184 | + # consumption and let your room heat/cool more gradually. |
| 185 | + - platform: template |
| 186 | + id: ${device_id}_max_temperature_delta |
| 187 | + name: Max temperature delta |
| 188 | + min_value: 0 |
| 189 | + max_value: 10 |
| 190 | + step: 0.25 |
| 191 | + initial_value: 2 |
| 192 | + optimistic: true |
| 193 | + on_value: |
| 194 | + - then: |
| 195 | + - lambda: id(${device_id}_calculated_external_sensor).update(); |
| 196 | + |
| 197 | +switch: |
| 198 | + - platform: MhiAcCtrl |
| 199 | + mhi_ac_ctrl_id: ${mhi_device_id} |
| 200 | + active_mode: |
| 201 | + name: Active mode |
| 202 | + id: ${device_id}_active_mode |
| 203 | + |
0 commit comments