Merge pull request #1 from SGXander/unformat-select

Unformat select
This commit is contained in:
SGXander 2023-12-19 00:49:08 +00:00 committed by GitHub
commit 9238542fb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 623 additions and 64 deletions

252
README.md
View File

@ -4,23 +4,28 @@ Wirelessly control your Mitsubishi Comfort HVAC equipment with an ESP8266 or
ESP32 using the [ESPHome](https://esphome.io) framework. ESP32 using the [ESPHome](https://esphome.io) framework.
## Features ## Features
* Instant feedback of command changes via RF Remote to HomeAssistant or MQTT. * Instant feedback of command changes via RF Remote to HomeAssistant or MQTT.
* Direct control without the remote. * Direct control without the remote.
* Uses the [SwiCago/HeatPump](https://github.com/SwiCago/HeatPump) Arduino * Uses the [SwiCago/HeatPump](https://github.com/SwiCago/HeatPump) Arduino
libary to talk to the unit directly via the internal `CN105` connector. libary to talk to the unit directly via the internal `CN105` connector.
## Requirements ## Requirements
* https://github.com/SwiCago/HeatPump
* [SwiCago/HeatPump](https://github.com/SwiCago/HeatPump)
* ESPHome 1.19.1 or greater * ESPHome 1.19.1 or greater
## Supported Microcontrollers ## Supported Microcontrollers
This library should work on most ESP8266 or ESP32 platforms. It has been tested This library should work on most ESP8266 or ESP32 platforms. It has been tested
with the following MCUs: with the following MCUs:
* Generic ESP-01S board (ESP8266) * Generic ESP-01S board (ESP8266)
* WeMos D1 Mini (ESP8266) * WeMos D1 Mini (ESP8266)
* Generic ESP32 Dev Kit (ESP32) * Generic ESP32 Dev Kit (ESP32)
## Supported Mitsubishi Climate Units ## Supported Mitsubishi Climate Units
The underlying HeatPump library works with a number of Mitsubishi HVAC The underlying HeatPump library works with a number of Mitsubishi HVAC
units. Basically, if the unit has a `CN105` header on the main board, it should units. Basically, if the unit has a `CN105` header on the main board, it should
work with this library. The [HeatPump work with this library. The [HeatPump
@ -34,11 +39,15 @@ available.
The whole integration with this libary and the underlying HeatPump has been The whole integration with this libary and the underlying HeatPump has been
tested by the author on the following units: tested by the author on the following units:
* `MSZ-GL06NA` * `MSZ-GL06NA`
* `MFZ-KA09NA` * `MFZ-KA09NA`
* `MSZ-FH35V`
* `MSZ-LN35VG2W`
## Usage ## Usage
### Step 1: Build a control circuit.
### Step 1: Build a control circuit
Build a control circuit with your MCU as detailed in the [SwiCago/HeatPump Build a control circuit with your MCU as detailed in the [SwiCago/HeatPump
README](https://github.com/SwiCago/HeatPump/blob/master/README.md#demo-circuit). README](https://github.com/SwiCago/HeatPump/blob/master/README.md#demo-circuit).
@ -70,6 +79,7 @@ external_components:
Version 2.0 and greater of this libary use the ESPHome `external_components` Version 2.0 and greater of this libary use the ESPHome `external_components`
feature, which is a huge step forward in terms of usability. In order to make feature, which is a huge step forward in terms of usability. In order to make
things compile correctly, you will need to: things compile correctly, you will need to:
1. Remove the `libraries` section that imports 1. Remove the `libraries` section that imports
`https://github.com/SwiCago/HeatPump`, as this is handled by the `https://github.com/SwiCago/HeatPump`, as this is handled by the
`external_component` section of manifest. `external_component` section of manifest.
@ -90,7 +100,8 @@ and `libraries` lines will likely result in compilation errors complaining
about duplicate declarations of `MitsubishiHeatPump::traits()`. about duplicate declarations of `MitsubishiHeatPump::traits()`.
##### Example error ##### Example error
```
```none
Linking /data/bedroom_east_heatpump/.pioenvs/bedroom_east_heatpump/firmware.elf Linking /data/bedroom_east_heatpump/.pioenvs/bedroom_east_heatpump/firmware.elf
/root/.platformio/packages/toolchain-xtensa/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/bin/ld: /data/bedroom_east_heatpump/.pioenvs/bedroom_east_heatpump/src/esphome/components/mitsubishi_heatpump/espmhp.cpp.o: in function `MitsubishiHeatPump::traits()': /root/.platformio/packages/toolchain-xtensa/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/bin/ld: /data/bedroom_east_heatpump/.pioenvs/bedroom_east_heatpump/src/esphome/components/mitsubishi_heatpump/espmhp.cpp.o: in function `MitsubishiHeatPump::traits()':
espmhp.cpp:(.text._ZN18MitsubishiHeatPump6traitsEv+0x4): multiple definition of `MitsubishiHeatPump::traits()'; /data/bedroom_east_heatpump/.pioenvs/bedroom_east_heatpump/src/esphome-mitsubishiheatpump/espmhp.cpp.o:espmhp.cpp:(.text._ZN18MitsubishiHeatPump6traitsEv+0x80): first defined here espmhp.cpp:(.text._ZN18MitsubishiHeatPump6traitsEv+0x4): multiple definition of `MitsubishiHeatPump::traits()'; /data/bedroom_east_heatpump/.pioenvs/bedroom_east_heatpump/src/esphome-mitsubishiheatpump/espmhp.cpp.o:espmhp.cpp:(.text._ZN18MitsubishiHeatPump6traitsEv+0x80): first defined here
@ -107,11 +118,14 @@ climate:
# Optional # Optional
hardware_uart: UART0 hardware_uart: UART0
baud_rate: 4800
# Optional # Optional
update_interval: 500ms update_interval: 500ms
``` ```
#### ESP8266 platforms
On ESP8266 you'll need to disable logging to serial because it conflicts with On ESP8266 you'll need to disable logging to serial because it conflicts with
the heatpump UART: the heatpump UART:
@ -120,8 +134,13 @@ logger:
baud_rate: 0 baud_rate: 0
``` ```
#### ESP32 platforms
On ESP32 you can change `hardware_uart` to `UART1` or `UART2` and keep logging On ESP32 you can change `hardware_uart` to `UART1` or `UART2` and keep logging
enabled on the main serial port. enabled on the main serial port. This may require specifying `baud_rate` on some
ESP32 boards.
#### UART Notes
*Note:* this component DOES NOT use the ESPHome `uart` component, as it *Note:* this component DOES NOT use the ESPHome `uart` component, as it
requires direct access to a hardware UART via the Arduino `HardwareSerial` requires direct access to a hardware UART via the Arduino `HardwareSerial`
@ -131,13 +150,15 @@ software serial libraries, including the one in ESPHome. There's currently no
way to guarantee access to a hardware UART nor retrieve the `HardwareSerial` way to guarantee access to a hardware UART nor retrieve the `HardwareSerial`
handle from the `uart` component within the ESPHome framework. handle from the `uart` component within the ESPHome framework.
# Example configuration ## Example configurations
Below is an example configuration which will include wireless strength Below is an example configuration which will include wireless strength
indicators and permit over the air updates. You'll need to create a indicators and permit over the air updates. You'll need to create a
`secrets.yaml` file inside of your `esphome` directory with entries for the `secrets.yaml` file inside of your `esphome` directory with entries for the
various items prefixed with `!secret`. various items prefixed with `!secret`.
### ESP8266 Example Configuration
```yaml ```yaml
substitutions: substitutions:
name: hptest name: hptest
@ -221,13 +242,110 @@ climate:
- platform: mitsubishi_heatpump - platform: mitsubishi_heatpump
name: "${friendly_name}" name: "${friendly_name}"
horizontal_vane_select:
name: Horizontal Vane
vertical_vane_select:
name: Vertical Vane
# ESP32 only - change UART0 to UART1 or UART2 and remove the # ESP32 only - change UART0 to UART1 or UART2 and remove the
# logging:baud_rate above to allow the built-in UART0 to function for # logging:baud_rate above to allow the built-in UART0 to function for
# logging. # logging.
# Some ESP32 boards will require the baud_rate setting if hardware_uart is specified.
hardware_uart: UART0 hardware_uart: UART0
baud_rate: 4800
``` ```
# Advanced configuration ### ESP32 Example Configuration
```yaml
substitutions:
name: hptest
friendly_name: Test Heatpump
esphome:
name: ${name}
esp32:
board: lolin_s2_mini
variant: ESP32S2
framework:
type: arduino
version: 2.0.3
platform_version: 5.0.0
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "${friendly_name} Fallback Hotspot"
password: !secret fallback_password
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
# Enable Web server.
web_server:
port: 80
# Sync time with Home Assistant.
time:
- platform: homeassistant
id: homeassistant_time
# Text sensors with general information.
text_sensor:
# Expose ESPHome version as sensor.
- platform: version
name: ${name} ESPHome Version
# Expose WiFi information as sensors.
- platform: wifi_info
ip_address:
name: ${name} IP
ssid:
name: ${name} SSID
bssid:
name: ${name} BSSID
# Sensors with general information.
sensor:
# Uptime sensor.
- platform: uptime
name: ${name} Uptime
# WiFi Signal sensor.
- platform: wifi_signal
name: ${name} WiFi Signal
update_interval: 60s
external_components:
- source: github://geoffdavis/esphome-mitsubishiheatpump
climate:
- platform: mitsubishi_heatpump
name: "${friendly_name}"
horizontal_vane_select:
name: Horizontal Vane
vertical_vane_select:
name: Vertical Vane
# ESP32 only - change UART0 to UART1 or UART2 and remove the
# logging:baud_rate above to allow the built-in UART0 to function for
# logging.
hardware_uart: UART1
```
### Advanced configuration
Some models of heat pump require different baud rates or don't support all Some models of heat pump require different baud rates or don't support all
possible modes of operation. You can configure mulitple climate "traits" in possible modes of operation. You can configure mulitple climate "traits" in
@ -239,10 +357,12 @@ climate:
name: "My heat pump" name: "My heat pump"
hardware_uart: UART2 hardware_uart: UART2
baud_rate: 9600 baud_rate: 9600
rx_pin: 9
tx_pin: 10
supports: supports:
mode: [HEAT_COOL, COOL, HEAT, FAN_ONLY] mode: ["HEAT_COOL", "COOL", "HEAT", "FAN_ONLY"]
fan_mode: [AUTO, LOW, MEDIUM, HIGH] fan_mode: ["AUTO", "LOW", "MEDIUM", "HIGH"]
swing_mode: [OFF, VERTICAL] swing_mode: ["OFF", "VERTICAL", "HORIZONTAL", "BOTH"]
visual: visual:
min_temperature: 16 min_temperature: 16
max_temperature: 31 max_temperature: 31
@ -251,40 +371,63 @@ climate:
## Configuration variables that affect this library directly ## Configuration variables that affect this library directly
* *hardware\_uart* (_Optional_): the hardware UART instance to use for * `hardware_uart` (_Optional_): the hardware UART instance to use for
communcation with the heatpump. On ESP8266, only `UART0` is usable. On ESP32, communcation with the heatpump. On ESP8266, only `UART0` is usable. On ESP32,
`UART0`, `UART1`, and `UART2` are all valid choices. Default: `UART0` `UART0`, `UART1`, and `UART2` are all valid choices. Default: `UART0`
* *baud\_rate* (_Optional_): Serial BAUD rate used to communicate with the * `baud_rate` (_Optional_): Serial BAUD rate used to communicate with the
HeatPump. Most systems use the default value of `4800` baud, but some use HeatPump. Most systems use the default value of `4800` baud, but some use
`9600`. Default: `4800` `2400` or `9600`. Check [here](https://github.com/SwiCago/HeatPump/issues/13)
* *update\_interval* (_Optional_, range: 0ms to 9000ms): How often this to find discussion of whether your particular model requires a non-default baud rate.
Some ESP32 boards will require the baud_rate setting if
hardware_uart is specified. Default: `4800`.
* `rx_pin` (_Optional_): pin number to use as RX for the specified hardware
UART (ESP32 only - ESP8266 hardware UART's pins aren't configurable).
* `tx_pin` (_Optional_): pin number to use as TX for the specified hardware
UART (ESP32 only - ESP8266 hardware UART's pins aren't configurable).
* `update_interval` (_Optional_, range: 0ms to 9000ms): How often this
component polls the heatpump hardware, in milliseconds. Maximum usable value component polls the heatpump hardware, in milliseconds. Maximum usable value
is 9 seconds due to underlying issues with the HeatPump library. Default: 500ms is 9 seconds due to underlying issues with the HeatPump library. Default: 500ms
* *supports* (_Optional_): Supported features for the device. ** *mode* * `supports` (_Optional_): Supported features for the device.
(_Optional_, list): Supported climate modes for the HeatPump. Default: * `mode` (_Optional_, list): Supported climate modes for the HeatPump. Default:
`['HEAT_COOL', 'COOL', 'HEAT', 'DRY', 'FAN_ONLY']` `['HEAT_COOL', 'COOL', 'HEAT', 'DRY', 'FAN_ONLY']`
** *fan_mode* (_Optional_, list): * `fan_mode` (_Optional_, list): Supported fan speeds for the HeatPump.
Supported fan speeds for the HeatPump. Default: `['AUTO', 'DIFFUSE', 'LOW', Default: `['AUTO', 'DIFFUSE', 'LOW', 'MEDIUM', 'MIDDLE', 'HIGH']`
'MEDIUM', 'MIDDLE', 'HIGH']` ** *swing_mode* (_Optional_, list): Supported * `swing_mode` (_Optional_, list): Supported fan swing modes. Most Mitsubishi
fan swing modes. Most Mitsubishi units only support the default. Default: units only support the default. Default: `['OFF', 'VERTICAL']`
`['OFF', 'VERTICAL']` * `remote_temperature_operating_timeout_minutes` (_Optional_): The number of
minutes before a set_remote_temperature request becomes stale, while the
heatpump is heating or cooling. Unless a new set_remote_temperature
request was made within the time duration, the heatpump will revert back to it's
internal temperature sensor.
* `remote_temperature_idle_timeout_minutes` (_Optional_): The number of
minutes before a set_remote_temperature request becomes stale while the heatpump
is idle. Unless a new set_remote_temperature request is made within the time duration,
the heatpump will revert back to it's internal temperature sensor.
* `remote_temperature_ping_timeout_minutes` (_Optional_): The number of
minutes before a set_remote_temperature request becomes stale, if a ping
request wasn't received from your ESPHome controller. This will result
in the heatpump reverting to it's internal temperature sensor if the heatpump
loses it's WiFi connection.
equest.)
## Other configuration ## Other configuration
* *id* (_Optional_): used to identify multiple instances, e.g. "denheatpump" * `id` (_Optional_): used to identify multiple instances, e.g. "denheatpump"
* *name* (_Required_): The name of the climate component, e.g. "Den Heatpump" * `name` (_Required_): The name of the climate component, e.g. "Den Heatpump"
* *visual* (_Optional_): The core `Climate` component has several *visual* * `visual` (_Optional_): The core `Climate` component has several *visual*
options that can be set. See the [Climate options that can be set. See the [Climate
Component](https://esphome.io/components/climate/index.html) documentation for Component](https://esphome.io/components/climate/index.html) documentation for
details. details.
## Remote temperature ### Remote temperature
It is possible to use an external temperature sensor to tell the heat pump what It is possible to use an external temperature sensor to tell the heat pump what
the room temperature is, rather than relying on its internal temperature the room temperature is, rather than relying on its internal temperature
sensor. You can do this by calling `set_remote_temperature(float temp)` on the sensor. This is helpful if you want to make sure that a particular room, or part
`mitsubishi_heatpump` object in a lambda. Note that you can call of the room, reaches the desired temperature—rather than just the area near the
`set_remote_temperature(0)` to switch back to the internal temperature sensor. heat pump or the thermostat. You can do this by calling `set_remote_temperature(float temp)`
on the `mitsubishi_heatpump` object in a lambda. (If needed, you can call
`set_remote_temperature(0)` to switch back to the internal temperature sensor.)
There are several ways you could make use of this functionality. One is to use There are several ways you could make use of this functionality. One is to use
a sensor automation: a sensor automation:
@ -296,7 +439,7 @@ climate:
id: hp id: hp
sensor: sensor:
# You could use a Bluetooth temperature sensor # You could use a Bluetooth temperature sensor as the source...
- platform: atc_mithermometer - platform: atc_mithermometer
mac_address: "XX:XX:XX:XX:XX:XX" mac_address: "XX:XX:XX:XX:XX:XX"
temperature: temperature:
@ -305,7 +448,7 @@ sensor:
then: then:
- lambda: 'id(hp).set_remote_temperature(x);' - lambda: 'id(hp).set_remote_temperature(x);'
# Or you could use a HomeAssistant sensor # ...or you could use a Home Assistant sensor as the source
- platform: homeassistant - platform: homeassistant
name: "Temperature Sensor From Home Assistant" name: "Temperature Sensor From Home Assistant"
entity_id: sensor.temperature_sensor entity_id: sensor.temperature_sensor
@ -313,8 +456,15 @@ sensor:
then: then:
- lambda: 'id(hp).set_remote_temperature(x);' - lambda: 'id(hp).set_remote_temperature(x);'
``` ```
One issue that you might have here is that, after some amount of time with no update from the
external temperature sensor, the heat pump will revert back to its internal temperature.
You can prevent this by [adding a `heartbeat` filter](https://github.com/geoffdavis/esphome-mitsubishiheatpump/issues/31#issuecomment-1207115352)
to the sensor, which will keep reminding the heat pump of the external sensor value.
Alternatively you could define a Also, if your external sensor is in Fahrenheit, you will have to [convert the value to Celsius](https://github.com/geoffdavis/esphome-mitsubishiheatpump/issues/31#issuecomment-1207115352).
Alternatively, you could define a
[service](https://www.esphome.io/components/api.html#user-defined-services) [service](https://www.esphome.io/components/api.html#user-defined-services)
that Home Assistant can call: that Home Assistant can call:
@ -332,9 +482,44 @@ api:
- lambda: 'id(hp).set_remote_temperature(0);' - lambda: 'id(hp).set_remote_temperature(0);'
``` ```
# See Also It's also possible to configure timeouts which will revert the heatpump
back to it's internal temperature sensor in the event that an external sensor
becomes unavailable. All three settings are optional, but it's recommended
that you configure both operating and idle timeout. Both can be configured to the same
value.
```yaml
climate:
- platform: mitsubishi_heatpump
remote_temperature_operating_timeout_minutes: 65
remote_temperature_idle_timeout_minutes: 120
remote_temperature_ping_timeout_minutes: 20
api:
services:
- service: ping
then:
- lambda: 'id(hp).ping();'
```
There is an explicit distinction between an operating timeout and an idle timeout.
* **Operating timeout** The heatpump is currently pumping heat, and the expectation is that
the temperature should shift within a certain time period. Recommended value: 60 minutes.
* **Idle timeout** The heatpump is not currently pumping heat, so temperature shifts are expected
to happen less frequently. Recommended value depends on the implementation details of your temperature
sensor. Some will only provide updates on temperature changes, others such as Aqara will provide
an update at least once every hour.
* **Ping timeout** Detects if a connection is lost between HomeAssistant and the heatpump, or if your
home assistant instance is down. Recommended value is 20 minutes, with a ping being sent every 5 minutes.
Do not enable ping timeout until you have the logic in place to call the ping service at a regular interval. You
can view the ESPHome logs to ensure this is taking place.
## See Also
### Other Implementations
## Other Implementations
The [gysmo38/mitsubishi2MQTT](https://github.com/gysmo38/mitsubishi2MQTT) The [gysmo38/mitsubishi2MQTT](https://github.com/gysmo38/mitsubishi2MQTT)
Arduino sketch also uses the `SwiCago/HeatPump` Arduino sketch also uses the `SwiCago/HeatPump`
library, and works with MQTT directly. The author of this implementation found library, and works with MQTT directly. The author of this implementation found
@ -351,9 +536,10 @@ repository and it's underlying `HeatPump` library allows bi-directional
communication with the Mitsubishi system, and can detect when someone changes communication with the Mitsubishi system, and can detect when someone changes
the settings via an IR remote. the settings via an IR remote.
## Reference documentation ### Reference documentation
The author referred to the following documentation repeatedly: The author referred to the following documentation repeatedly:
* [ESPHome Custom Sensors Reference](https://esphome.io/components/sensor/custom.html) * [ESPHome Custom Sensors Reference](https://esphome.io/components/sensor/custom.html)
* [ESPHome Custom Climate Components Reference](https://esphome.io/components/climate/custom.html) * [ESPHome Custom Climate Components Reference](https://esphome.io/components/climate/custom.html)
* [ESPHome External Components Reference](https://esphome.io/components/external_components.html) * [ESPHome External Components Reference](https://esphome.io/components/external_components.html)

View File

@ -1,11 +1,13 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import climate from esphome.components import climate, select
from esphome.components.logger import HARDWARE_UART_TO_SERIAL from esphome.components.logger import HARDWARE_UART_TO_SERIAL
from esphome.const import ( from esphome.const import (
CONF_ID, CONF_ID,
CONF_HARDWARE_UART, CONF_HARDWARE_UART,
CONF_BAUD_RATE, CONF_BAUD_RATE,
CONF_RX_PIN,
CONF_TX_PIN,
CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL,
CONF_MODE, CONF_MODE,
CONF_FAN_MODE, CONF_FAN_MODE,
@ -13,17 +15,29 @@ from esphome.const import (
) )
from esphome.core import CORE, coroutine from esphome.core import CORE, coroutine
AUTO_LOAD = ["climate"] AUTO_LOAD = ["climate", "select"]
CONF_SUPPORTS = "supports" CONF_SUPPORTS = "supports"
CONF_HORIZONTAL_SWING_SELECT = "horizontal_vane_select"
CONF_VERTICAL_SWING_SELECT = "vertical_vane_select"
DEFAULT_CLIMATE_MODES = ["HEAT_COOL", "COOL", "HEAT", "DRY", "FAN_ONLY"] DEFAULT_CLIMATE_MODES = ["HEAT_COOL", "COOL", "HEAT", "DRY", "FAN_ONLY"]
DEFAULT_FAN_MODES = ["AUTO", "DIFFUSE", "LOW", "MEDIUM", "MIDDLE", "HIGH"] DEFAULT_FAN_MODES = ["AUTO", "DIFFUSE", "LOW", "MEDIUM", "MIDDLE", "HIGH"]
DEFAULT_SWING_MODES = ["OFF", "VERTICAL"] DEFAULT_SWING_MODES = ["OFF", "VERTICAL"]
HORIZONTAL_SWING_OPTIONS = ["auto","left","left_center","center","right_center","right","swing"]
VERTICAL_SWING_OPTIONS = ["auto", "up", "up_center", "center", "down_center", "down","swing"]
# Remote temperature timeout configuration
CONF_REMOTE_OPERATING_TIMEOUT = "remote_temperature_operating_timeout_minutes"
CONF_REMOTE_IDLE_TIMEOUT = "remote_temperature_idle_timeout_minutes"
CONF_REMOTE_PING_TIMEOUT = "remote_temperature_ping_timeout_minutes"
MitsubishiHeatPump = cg.global_ns.class_( MitsubishiHeatPump = cg.global_ns.class_(
"MitsubishiHeatPump", climate.Climate, cg.PollingComponent "MitsubishiHeatPump", climate.Climate, cg.PollingComponent
) )
MitsubishiACSelect = cg.global_ns.class_(
"MitsubishiACSelect", select.Select, cg.Component
)
def valid_uart(uart): def valid_uart(uart):
if CORE.is_esp8266: if CORE.is_esp8266:
@ -36,16 +50,28 @@ def valid_uart(uart):
return cv.one_of(*uarts, upper=True)(uart) return cv.one_of(*uarts, upper=True)(uart)
SELECT_SCHEMA = select.SELECT_SCHEMA.extend(
{cv.GenerateID(CONF_ID): cv.declare_id(MitsubishiACSelect)}
)
CONFIG_SCHEMA = climate.CLIMATE_SCHEMA.extend( CONFIG_SCHEMA = climate.CLIMATE_SCHEMA.extend(
{ {
cv.GenerateID(): cv.declare_id(MitsubishiHeatPump), cv.GenerateID(): cv.declare_id(MitsubishiHeatPump),
cv.Optional(CONF_HARDWARE_UART, default="UART0"): valid_uart, cv.Optional(CONF_HARDWARE_UART, default="UART0"): valid_uart,
cv.Optional(CONF_BAUD_RATE): cv.positive_int, cv.Optional(CONF_BAUD_RATE): cv.positive_int,
cv.Optional(CONF_REMOTE_OPERATING_TIMEOUT): cv.positive_int,
cv.Optional(CONF_REMOTE_IDLE_TIMEOUT): cv.positive_int,
cv.Optional(CONF_REMOTE_PING_TIMEOUT): cv.positive_int,
cv.Optional(CONF_RX_PIN): cv.positive_int,
cv.Optional(CONF_TX_PIN): cv.positive_int,
# If polling interval is greater than 9 seconds, the HeatPump library # If polling interval is greater than 9 seconds, the HeatPump library
# reconnects, but doesn't then follow up with our data request. # reconnects, but doesn't then follow up with our data request.
cv.Optional(CONF_UPDATE_INTERVAL, default="500ms"): cv.All( cv.Optional(CONF_UPDATE_INTERVAL, default="500ms"): cv.All(
cv.update_interval, cv.Range(max=cv.TimePeriod(milliseconds=9000)) cv.update_interval, cv.Range(max=cv.TimePeriod(milliseconds=9000))
), ),
# Add selects for vertical and horizontal vane positions
cv.Optional(CONF_HORIZONTAL_SWING_SELECT): SELECT_SCHEMA,
cv.Optional(CONF_VERTICAL_SWING_SELECT): SELECT_SCHEMA,
# Optionally override the supported ClimateTraits. # Optionally override the supported ClimateTraits.
cv.Optional(CONF_SUPPORTS, default={}): cv.Schema( cv.Optional(CONF_SUPPORTS, default={}): cv.Schema(
{ {
@ -69,6 +95,22 @@ def to_code(config):
if CONF_BAUD_RATE in config: if CONF_BAUD_RATE in config:
cg.add(var.set_baud_rate(config[CONF_BAUD_RATE])) cg.add(var.set_baud_rate(config[CONF_BAUD_RATE]))
if CONF_RX_PIN in config:
cg.add(var.set_rx_pin(config[CONF_RX_PIN]))
if CONF_TX_PIN in config:
cg.add(var.set_tx_pin(config[CONF_TX_PIN]))
if CONF_REMOTE_OPERATING_TIMEOUT in config:
cg.add(var.set_remote_operating_timeout_minutes(config[CONF_REMOTE_OPERATING_TIMEOUT]))
if CONF_REMOTE_IDLE_TIMEOUT in config:
cg.add(var.set_remote_idle_timeout_minutes(config[CONF_REMOTE_IDLE_TIMEOUT]))
if CONF_REMOTE_PING_TIMEOUT in config:
cg.add(var.set_remote_ping_timeout_minutes(config[CONF_REMOTE_PING_TIMEOUT]))
supports = config[CONF_SUPPORTS] supports = config[CONF_SUPPORTS]
traits = var.config_traits() traits = var.config_traits()
@ -85,6 +127,18 @@ def to_code(config):
climate.CLIMATE_SWING_MODES[mode] climate.CLIMATE_SWING_MODES[mode]
)) ))
if CONF_HORIZONTAL_SWING_SELECT in config:
conf = config[CONF_HORIZONTAL_SWING_SELECT]
swing_select = yield select.new_select(conf, options=HORIZONTAL_SWING_OPTIONS)
yield cg.register_component(swing_select, conf)
cg.add(var.set_horizontal_vane_select(swing_select))
if CONF_VERTICAL_SWING_SELECT in config:
conf = config[CONF_VERTICAL_SWING_SELECT]
swing_select = yield select.new_select(conf, options=VERTICAL_SWING_OPTIONS)
yield cg.register_component(swing_select, conf)
cg.add(var.set_vertical_vane_select(swing_select))
yield cg.register_component(var, config) yield cg.register_component(var, config)
yield climate.register_climate(var, config) yield climate.register_climate(var, config)
cg.add_library( cg.add_library(

View File

@ -9,7 +9,8 @@
* Author: @am-io on Github. * Author: @am-io on Github.
* Author: @nao-pon on Github. * Author: @nao-pon on Github.
* Author: Simon Knopp @sijk on Github * Author: Simon Knopp @sijk on Github
* Last Updated: 2021-05-27 * Author: Paul Murphy @donutsoft on GitHub
* Last Updated: 2023-04-22
* License: BSD * License: BSD
* *
* Requirements: * Requirements:
@ -40,6 +41,10 @@ MitsubishiHeatPump::MitsubishiHeatPump(
this->traits_.set_visual_min_temperature(ESPMHP_MIN_TEMPERATURE); this->traits_.set_visual_min_temperature(ESPMHP_MIN_TEMPERATURE);
this->traits_.set_visual_max_temperature(ESPMHP_MAX_TEMPERATURE); this->traits_.set_visual_max_temperature(ESPMHP_MAX_TEMPERATURE);
this->traits_.set_visual_temperature_step(ESPMHP_TEMPERATURE_STEP); this->traits_.set_visual_temperature_step(ESPMHP_TEMPERATURE_STEP);
// Assume a succesful connection was made to the ESPHome controller on
// launch.
this->ping();
} }
void MitsubishiHeatPump::check_logger_conflict_() { void MitsubishiHeatPump::check_logger_conflict_() {
@ -53,6 +58,11 @@ void MitsubishiHeatPump::check_logger_conflict_() {
#endif #endif
} }
void MitsubishiHeatPump::banner() {
ESP_LOGI(TAG, "ESPHome MitsubishiHeatPump version %s",
ESPMHP_VERSION);
}
void MitsubishiHeatPump::update() { void MitsubishiHeatPump::update() {
// This will be called every "update_interval" milliseconds. // This will be called every "update_interval" milliseconds.
//this->dump_config(); //this->dump_config();
@ -62,12 +72,21 @@ void MitsubishiHeatPump::update() {
heatpumpStatus currentStatus = hp->getStatus(); heatpumpStatus currentStatus = hp->getStatus();
this->hpStatusChanged(currentStatus); this->hpStatusChanged(currentStatus);
#endif #endif
this->enforce_remote_temperature_sensor_timeout();
} }
void MitsubishiHeatPump::set_baud_rate(int baud) { void MitsubishiHeatPump::set_baud_rate(int baud) {
this->baud_ = baud; this->baud_ = baud;
} }
void MitsubishiHeatPump::set_rx_pin(int rx_pin) {
this->rx_pin_ = rx_pin;
}
void MitsubishiHeatPump::set_tx_pin(int tx_pin) {
this->tx_pin_ = tx_pin;
}
/** /**
* Get our supported traits. * Get our supported traits.
* *
@ -92,6 +111,117 @@ climate::ClimateTraits& MitsubishiHeatPump::config_traits() {
return traits_; return traits_;
} }
void MitsubishiHeatPump::update_swing_horizontal(const std::string &swing) {
this->horizontal_swing_state_ = swing;
if (this->horizontal_vane_select_ != nullptr &&
this->horizontal_vane_select_->state != this->horizontal_swing_state_) {
this->horizontal_vane_select_->publish_state(
this->horizontal_swing_state_); // Set current horizontal swing
// position
}
}
void MitsubishiHeatPump::update_swing_vertical(const std::string &swing) {
this->vertical_swing_state_ = swing;
if (this->vertical_vane_select_ != nullptr &&
this->vertical_vane_select_->state != this->vertical_swing_state_) {
this->vertical_vane_select_->publish_state(
this->vertical_swing_state_); // Set current vertical swing position
}
}
void MitsubishiHeatPump::set_vertical_vane_select(
select::Select *vertical_vane_select) {
this->vertical_vane_select_ = vertical_vane_select;
this->vertical_vane_select_->add_on_state_callback(
[this](const std::string &value, size_t index) {
if (value == this->vertical_swing_state_) return;
this->on_vertical_swing_change(value);
});
}
void MitsubishiHeatPump::set_horizontal_vane_select(
select::Select *horizontal_vane_select) {
this->horizontal_vane_select_ = horizontal_vane_select;
this->horizontal_vane_select_->add_on_state_callback(
[this](const std::string &value, size_t index) {
if (value == this->horizontal_swing_state_) return;
this->on_horizontal_swing_change(value);
});
}
void MitsubishiHeatPump::on_vertical_swing_change(const std::string &swing) {
ESP_LOGD(TAG, "Setting vertical swing position");
bool updated = false;
if (swing == "swing") {
hp->setVaneSetting("SWING");
updated = true;
} else if (swing == "auto") {
hp->setVaneSetting("AUTO");
updated = true;
} else if (swing == "up") {
hp->setVaneSetting("1");
updated = true;
} else if (swing == "up_center") {
hp->setVaneSetting("2");
updated = true;
} else if (swing == "center") {
hp->setVaneSetting("3");
updated = true;
} else if (swing == "down_center") {
hp->setVaneSetting("4");
updated = true;
} else if (swing == "down") {
hp->setVaneSetting("5");
updated = true;
} else {
ESP_LOGW(TAG, "Invalid vertical vane position %s", swing);
}
ESP_LOGD(TAG, "Vertical vane - Was HeatPump updated? %s", YESNO(updated));
// and the heat pump:
hp->update();
}
void MitsubishiHeatPump::on_horizontal_swing_change(const std::string &swing) {
ESP_LOGD(TAG, "Setting horizontal swing position");
bool updated = false;
if (swing == "swing") {
hp->setWideVaneSetting("SWING");
updated = true;
} else if (swing == "auto") {
hp->setWideVaneSetting("<>");
updated = true;
} else if (swing == "left") {
hp->setWideVaneSetting("<<");
updated = true;
} else if (swing == "left_center") {
hp->setWideVaneSetting("<");
updated = true;
} else if (swing == "center") {
hp->setWideVaneSetting("|");
updated = true;
} else if (swing == "right_center") {
hp->setWideVaneSetting(">");
updated = true;
} else if (swing == "right") {
hp->setWideVaneSetting(">>");
updated = true;
} else {
ESP_LOGW(TAG, "Invalid horizontal vane position %s", swing);
}
ESP_LOGD(TAG, "Horizontal vane - Was HeatPump updated? %s", YESNO(updated));
// and the heat pump:
hp->update();
}
/** /**
* Implement control of a MitsubishiHeatPump. * Implement control of a MitsubishiHeatPump.
* *
@ -106,6 +236,24 @@ void MitsubishiHeatPump::control(const climate::ClimateCall &call) {
if (has_mode){ if (has_mode){
this->mode = *call.get_mode(); this->mode = *call.get_mode();
} }
if (last_remote_temperature_sensor_update_.has_value()) {
// Some remote temperature sensors will only issue updates when a change
// in temperature occurs.
// Assume a case where the idle sensor timeout is 12hrs and operating
// timeout is 1hr. If the user changes the HP setpoint after 1.5hrs, the
// machine will switch to operating mode, the remote temperature
// reading will expire and the HP will revert to it's internal
// temperature sensor.
// This change ensures that if the user changes the machine setpoint,
// the remote sensor has an opportunity to issue an update to reflect
// the new change in temperature.
last_remote_temperature_sensor_update_ =
std::chrono::steady_clock::now();
}
switch (this->mode) { switch (this->mode) {
case climate::CLIMATE_MODE_COOL: case climate::CLIMATE_MODE_COOL:
hp->setModeSetting("COOL"); hp->setModeSetting("COOL");
@ -227,10 +375,22 @@ void MitsubishiHeatPump::control(const climate::ClimateCall &call) {
switch(*call.get_swing_mode()) { switch(*call.get_swing_mode()) {
case climate::CLIMATE_SWING_OFF: case climate::CLIMATE_SWING_OFF:
hp->setVaneSetting("AUTO"); hp->setVaneSetting("AUTO");
hp->setWideVaneSetting("|");
updated = true; updated = true;
break; break;
case climate::CLIMATE_SWING_VERTICAL: case climate::CLIMATE_SWING_VERTICAL:
hp->setVaneSetting("SWING"); hp->setVaneSetting("SWING");
hp->setWideVaneSetting("|");
updated = true;
break;
case climate::CLIMATE_SWING_HORIZONTAL:
hp->setVaneSetting("3");
hp->setWideVaneSetting("SWING");
updated = true;
break;
case climate::CLIMATE_SWING_BOTH:
hp->setVaneSetting("SWING");
hp->setWideVaneSetting("SWING");
updated = true; updated = true;
break; break;
default: default:
@ -333,15 +493,52 @@ void MitsubishiHeatPump::hpSettingsChanged() {
/* ******** HANDLE MITSUBISHI VANE CHANGES ******** /* ******** HANDLE MITSUBISHI VANE CHANGES ********
* const char* VANE_MAP[7] = {"AUTO", "1", "2", "3", "4", "5", "SWING"}; * const char* VANE_MAP[7] = {"AUTO", "1", "2", "3", "4", "5", "SWING"};
*/ */
if (strcmp(currentSettings.vane, "SWING") == 0) { if (strcmp(currentSettings.vane, "SWING") == 0 &&
strcmp(currentSettings.wideVane, "SWING") == 0) {
this->swing_mode = climate::CLIMATE_SWING_BOTH;
} else if (strcmp(currentSettings.vane, "SWING") == 0) {
this->swing_mode = climate::CLIMATE_SWING_VERTICAL; this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
} } else if (strcmp(currentSettings.wideVane, "SWING") == 0) {
else { this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
} else {
this->swing_mode = climate::CLIMATE_SWING_OFF; this->swing_mode = climate::CLIMATE_SWING_OFF;
} }
ESP_LOGI(TAG, "Swing mode is: %i", this->swing_mode); ESP_LOGI(TAG, "Swing mode is: %i", this->swing_mode);
if (strcmp(currentSettings.vane, "SWING") == 0) {
this->update_swing_vertical("swing");
} else if (strcmp(currentSettings.vane, "AUTO") == 0) {
this->update_swing_vertical("auto");
} else if (strcmp(currentSettings.vane, "1") == 0) {
this->update_swing_vertical("up");
} else if (strcmp(currentSettings.vane, "2") == 0) {
this->update_swing_vertical("up_center");
} else if (strcmp(currentSettings.vane, "3") == 0) {
this->update_swing_vertical("center");
} else if (strcmp(currentSettings.vane, "4") == 0) {
this->update_swing_vertical("down_center");
} else if (strcmp(currentSettings.vane, "5") == 0) {
this->update_swing_vertical("down");
}
ESP_LOGI(TAG, "Vertical vane mode is: %s", currentSettings.vane);
if (strcmp(currentSettings.wideVane, "SWING") == 0) {
this->update_swing_horizontal("swing");
} else if (strcmp(currentSettings.wideVane, "<>") == 0) {
this->update_swing_horizontal("auto");
} else if (strcmp(currentSettings.wideVane, "<<") == 0) {
this->update_swing_horizontal("left");
} else if (strcmp(currentSettings.wideVane, "<") == 0) {
this->update_swing_horizontal("left_center");
} else if (strcmp(currentSettings.wideVane, "|") == 0) {
this->update_swing_horizontal("center");
} else if (strcmp(currentSettings.wideVane, ">") == 0) {
this->update_swing_horizontal("right_center");
} else if (strcmp(currentSettings.wideVane, ">>") == 0) {
this->update_swing_horizontal("right");
}
ESP_LOGI(TAG, "Horizontal vane mode is: %s", currentSettings.wideVane);
/* /*
* ******** HANDLE TARGET TEMPERATURE CHANGES ******** * ******** HANDLE TARGET TEMPERATURE CHANGES ********
@ -402,14 +599,71 @@ void MitsubishiHeatPump::hpStatusChanged(heatpumpStatus currentStatus) {
this->action = climate::CLIMATE_ACTION_OFF; this->action = climate::CLIMATE_ACTION_OFF;
} }
this->operating_ = currentStatus.operating;
this->publish_state(); this->publish_state();
} }
void MitsubishiHeatPump::set_remote_temperature(float temp) { void MitsubishiHeatPump::set_remote_temperature(float temp) {
ESP_LOGD(TAG, "Setting remote temp: %.1f", temp); ESP_LOGD(TAG, "Setting remote temp: %.1f", temp);
if (temp > 0) {
last_remote_temperature_sensor_update_ =
std::chrono::steady_clock::now();
} else {
last_remote_temperature_sensor_update_.reset();
}
this->hp->setRemoteTemperature(temp); this->hp->setRemoteTemperature(temp);
} }
void MitsubishiHeatPump::ping() {
ESP_LOGD(TAG, "Ping request received");
last_ping_request_ = std::chrono::steady_clock::now();
}
void MitsubishiHeatPump::set_remote_operating_timeout_minutes(int minutes) {
ESP_LOGD(TAG, "Setting remote operating timeout time: %d minutes", minutes);
remote_operating_timeout_ = std::chrono::minutes(minutes);
}
void MitsubishiHeatPump::set_remote_idle_timeout_minutes(int minutes) {
ESP_LOGD(TAG, "Setting remote idle timeout time: %d minutes", minutes);
remote_idle_timeout_ = std::chrono::minutes(minutes);
}
void MitsubishiHeatPump::set_remote_ping_timeout_minutes(int minutes) {
ESP_LOGD(TAG, "Setting remote ping timeout time: %d minutes", minutes);
remote_ping_timeout_ = std::chrono::minutes(minutes);
}
void MitsubishiHeatPump::enforce_remote_temperature_sensor_timeout() {
// Handle ping timeouts.
if (remote_ping_timeout_.has_value() && last_ping_request_.has_value()) {
auto time_since_last_ping =
std::chrono::steady_clock::now() - last_ping_request_.value();
if(time_since_last_ping > remote_ping_timeout_.value()) {
ESP_LOGW(TAG, "Ping timeout.");
this->set_remote_temperature(0);
last_ping_request_.reset();
return;
}
}
// Handle set_remote_temperature timeouts.
auto remote_set_temperature_timeout =
this->operating_ ? remote_operating_timeout_ : remote_idle_timeout_;
if (remote_set_temperature_timeout.has_value() &&
last_remote_temperature_sensor_update_.has_value()) {
auto time_since_last_temperature_update =
std::chrono::steady_clock::now() - last_remote_temperature_sensor_update_.value();
if (time_since_last_temperature_update > remote_set_temperature_timeout.value()) {
ESP_LOGW(TAG, "Set remote temperature timeout, operating=%d", this->operating_);
this->set_remote_temperature(0);
return;
}
}
}
void MitsubishiHeatPump::setup() { void MitsubishiHeatPump::setup() {
// This will be called by App.setup() // This will be called by App.setup()
this->banner(); this->banner();
@ -431,6 +685,8 @@ void MitsubishiHeatPump::setup() {
this->target_temperature = NAN; this->target_temperature = NAN;
this->fan_mode = climate::CLIMATE_FAN_OFF; this->fan_mode = climate::CLIMATE_FAN_OFF;
this->swing_mode = climate::CLIMATE_SWING_OFF; this->swing_mode = climate::CLIMATE_SWING_OFF;
this->vertical_swing_state_ = "auto";
this->horizontal_swing_state_ = "auto";
#ifdef USE_CALLBACKS #ifdef USE_CALLBACKS
hp->setSettingsChangedCallback( hp->setSettingsChangedCallback(
@ -451,12 +707,11 @@ void MitsubishiHeatPump::setup() {
"hw_serial(%p) is &Serial(%p)? %s", "hw_serial(%p) is &Serial(%p)? %s",
this->get_hw_serial_(), this->get_hw_serial_(),
&Serial, &Serial,
YESNO(this->get_hw_serial_() == &Serial) YESNO((void *)this->get_hw_serial_() == (void *)&Serial)
); );
ESP_LOGCONFIG(TAG, "Calling hp->connect(%p)", this->get_hw_serial_()); ESP_LOGCONFIG(TAG, "Calling hp->connect(%p)", this->get_hw_serial_());
if (hp->connect(this->get_hw_serial_(), this->baud_, this->rx_pin_, this->tx_pin_)) {
if (hp->connect(this->get_hw_serial_(), this->baud_, -1, -1)) {
hp->sync(); hp->sync();
} }
else { else {

View File

@ -18,10 +18,11 @@
#define USE_CALLBACKS #define USE_CALLBACKS
#include "esphome.h" #include "esphome.h"
#include "esphome/components/select/select.h"
#include "esphome/core/preferences.h" #include "esphome/core/preferences.h"
#include <chrono>
#include "HeatPump.h" #include "HeatPump.h"
using namespace esphome;
#ifndef ESPMHP_H #ifndef ESPMHP_H
#define ESPMHP_H #define ESPMHP_H
@ -41,7 +42,7 @@ static const uint8_t ESPMHP_MAX_TEMPERATURE = 31; // degrees C,
static const float ESPMHP_TEMPERATURE_STEP = 0.5; // temperature setting step, static const float ESPMHP_TEMPERATURE_STEP = 0.5; // temperature setting step,
// in degrees C // in degrees C
class MitsubishiHeatPump : public PollingComponent, public climate::Climate { class MitsubishiHeatPump : public esphome::PollingComponent, public esphome::climate::Climate {
public: public:
@ -58,14 +59,17 @@ class MitsubishiHeatPump : public PollingComponent, public climate::Climate {
); );
// Print a banner with library information. // Print a banner with library information.
void banner() { void banner();
ESP_LOGI(TAG, "ESPHome MitsubishiHeatPump version %s",
ESPMHP_VERSION);
}
// Set the baud rate. Must be called before setup() to have any effect. // Set the baud rate. Must be called before setup() to have any effect.
void set_baud_rate(int); void set_baud_rate(int);
// Set the RX pin. Must be called before setup() to have any effect.
void set_rx_pin(int);
// Set the TX pin. Must be called before setup() to have any effect.
void set_tx_pin(int);
// print the current configuration // print the current configuration
void dump_config() override; void dump_config() override;
@ -82,27 +86,52 @@ class MitsubishiHeatPump : public PollingComponent, public climate::Climate {
void update() override; void update() override;
// Configure the climate object with traits that we support. // Configure the climate object with traits that we support.
climate::ClimateTraits traits() override; esphome::climate::ClimateTraits traits() override;
// Get a mutable reference to the traits that we support. // Get a mutable reference to the traits that we support.
climate::ClimateTraits& config_traits(); esphome::climate::ClimateTraits& config_traits();
// Debugging function to print the object's state. // Debugging function to print the object's state.
void dump_state(); void dump_state();
// Handle a request from the user to change settings. // Handle a request from the user to change settings.
void control(const climate::ClimateCall &call) override; void control(const esphome::climate::ClimateCall &call) override;
// Use the temperature from an external sensor. Use // Use the temperature from an external sensor. Use
// set_remote_temp(0) to switch back to the internal sensor. // set_remote_temp(0) to switch back to the internal sensor.
void set_remote_temperature(float); void set_remote_temperature(float);
void set_vertical_vane_select(esphome::select::Select *vertical_vane_select);
void set_horizontal_vane_select(esphome::select::Select *horizontal_vane_select);
// Used to validate that a connection is present between the controller
// and this heatpump.
void ping();
// Number of minutes before the heatpump reverts back to the internal
// temperature sensor if the machine is currently operating.
void set_remote_operating_timeout_minutes(int);
// Number of minutes before the heatpump reverts back to the internal
// temperature sensor if the machine is currently idle.
void set_remote_idle_timeout_minutes(int);
// Number of minutes before the heatpump reverts back to the internal
// temperature sensor if a ping isn't received from the controller.
void set_remote_ping_timeout_minutes(int);
protected: protected:
// HeatPump object using the underlying Arduino library. // HeatPump object using the underlying Arduino library.
HeatPump* hp; HeatPump* hp;
// The ClimateTraits supported by this HeatPump. // The ClimateTraits supported by this HeatPump.
climate::ClimateTraits traits_; esphome::climate::ClimateTraits traits_;
// Vane position
void update_swing_horizontal(const std::string &swing);
void update_swing_vertical(const std::string &swing);
std::string vertical_swing_state_;
std::string horizontal_swing_state_;
// Allow the HeatPump class to use get_hw_serial_ // Allow the HeatPump class to use get_hw_serial_
friend class HeatPump; friend class HeatPump;
@ -118,21 +147,41 @@ class MitsubishiHeatPump : public PollingComponent, public climate::Climate {
// various prefs to save mode-specific temperatures, akin to how the IR // various prefs to save mode-specific temperatures, akin to how the IR
// remote works. // remote works.
ESPPreferenceObject cool_storage; esphome::ESPPreferenceObject cool_storage;
ESPPreferenceObject heat_storage; esphome::ESPPreferenceObject heat_storage;
ESPPreferenceObject auto_storage; esphome::ESPPreferenceObject auto_storage;
optional<float> cool_setpoint; esphome::optional<float> cool_setpoint;
optional<float> heat_setpoint; esphome::optional<float> heat_setpoint;
optional<float> auto_setpoint; esphome::optional<float> auto_setpoint;
static void save(float value, ESPPreferenceObject& storage); static void save(float value, esphome::ESPPreferenceObject& storage);
static optional<float> load(ESPPreferenceObject& storage); static esphome::optional<float> load(esphome::ESPPreferenceObject& storage);
esphome::select::Select *vertical_vane_select_ =
nullptr; // Select to store manual position of vertical swing
esphome::select::Select *horizontal_vane_select_ =
nullptr; // Select to store manual position of horizontal swing
// When received command to change the vane positions
void on_horizontal_swing_change(const std::string &swing);
void on_vertical_swing_change(const std::string &swing);
private: private:
void enforce_remote_temperature_sensor_timeout();
// Retrieve the HardwareSerial pointer from friend and subclasses. // Retrieve the HardwareSerial pointer from friend and subclasses.
HardwareSerial *hw_serial_; HardwareSerial *hw_serial_;
int baud_ = 0; int baud_ = 0;
int rx_pin_ = -1;
int tx_pin_ = -1;
bool operating_ = false;
std::optional<std::chrono::duration<long long, std::ratio<60>>> remote_operating_timeout_;
std::optional<std::chrono::duration<long long, std::ratio<60>>> remote_idle_timeout_;
std::optional<std::chrono::duration<long long, std::ratio<60>>> remote_ping_timeout_;
std::optional<std::chrono::time_point<std::chrono::steady_clock>> last_remote_temperature_sensor_update_;
std::optional<std::chrono::time_point<std::chrono::steady_clock>> last_ping_request_;
}; };
#endif #endif

View File

@ -0,0 +1,15 @@
#pragma once
#include "esphome/components/select/select.h"
#include "esphome/core/component.h"
namespace esphome {
class MitsubishiACSelect : public select::Select, public Component {
protected:
void control(const std::string &value) override {
this->publish_state(value);
}
};
} // namespace esphome