Class: ESPHome::Entities::Climate

Inherits:
ESPHome::Entity show all
Includes:
HasState
Defined in:
lib/esphome/entities/climate.rb

Defined Under Namespace

Modules: Features

Constant Summary collapse

UNIT_SYMBOLS =
{
  celsius: "°C",
  fahrenheit: "°F",
  kelvin: "K"
}.freeze

Instance Attribute Summary collapse

Attributes inherited from ESPHome::Entity

#device, #disabled_by_default, #entity_category, #icon, #key, #name, #object_id_

Instance Method Summary collapse

Methods inherited from ESPHome::Entity

#inspect

Constructor Details

#initialize(_device, list_entities_response) ⇒ Climate

Returns a new instance of Climate.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/esphome/entities/climate.rb', line 54

def initialize(_device, list_entities_response)
  super

  if list_entities_response.feature_flags
    @supports_current_temperature = list_entities_response.feature_flags.anybits?(Features::SUPPORTS_CURRENT_TEMPERATURE)
    @supports_two_point_target_temperature = list_entities_response.feature_flags.anybits?(Features::SUPPORTS_TWO_POINT_TARGET_TEMPERATURE)
    @supports_current_humidity = list_entities_response.feature_flags.anybits?(Features::SUPPORTS_CURRENT_HUMIDITY)
    @supports_target_humidity = list_entities_response.feature_flags.anybits?(Features::SUPPORTS_TARGET_HUMIDITY)
    @supports_action = list_entities_response.feature_flags.anybits?(Features::SUPPORTS_ACTION)
  else
    @supports_current_temperature = list_entities_response.supports_current_temperature
    @supports_two_point_target_temperature = list_entities_response.supports_two_point_target_temperature
    @supports_current_humidity = list_entities_response.supports_current_humidity
    @supports_target_humidity = list_entities_response.supports_target_humidity
    @supports_action = list_entities_response.supports_action
  end
  @supported_modes = list_entities_response.supported_modes.map { |m| m[13..].downcase.to_sym }.freeze
  @visual_temperature_range = Range.new(list_entities_response.visual_min_temperature,
                                        list_entities_response.visual_max_temperature)
  @visual_target_temperature_step = list_entities_response.visual_target_temperature_step
  @supported_fan_modes = list_entities_response.supported_fan_modes.map { |m| m[12..].downcase.to_sym }
  @supported_swing_modes = list_entities_response.supported_swing_modes.map { |m| m[14..].downcase.to_sym }.freeze
  @supported_fan_modes.concat(list_entities_response.supported_custom_fan_modes.map(&:to_sym))
  @supported_fan_modes.freeze
  @supported_presets = list_entities_response.supported_presets.map { |p| p[15..].downcase.to_sym }
  if list_entities_response.legacy_supports_away && !@supported_presets.include?(:away)
    @supported_presets.push(:away)
  end
  @supported_presets.concat(list_entities_response.supported_custom_presets.map(&:to_sym))
  @supported_presets.freeze
  @visual_humidity_range = Range.new(list_entities_response.visual_min_humidity,
                                     list_entities_response.visual_max_humidity)
  @temperature_unit = list_entities_response.temperature_unit&.[](17..)&.downcase&.to_sym || :celsius
end

Instance Attribute Details

#actionObject (readonly)

Returns the value of attribute action.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def action
  @action
end

#current_humidityObject (readonly)

Returns the value of attribute current_humidity.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def current_humidity
  @current_humidity
end

#current_temperatureObject (readonly)

Returns the value of attribute current_temperature.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def current_temperature
  @current_temperature
end

#fan_modeObject (readonly)

Returns the value of attribute fan_mode.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def fan_mode
  @fan_mode
end

#presetObject (readonly)

Returns the value of attribute preset.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def preset
  @preset
end

#supported_fan_modesObject (readonly)

Returns the value of attribute supported_fan_modes.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def supported_fan_modes
  @supported_fan_modes
end

#supported_modesObject (readonly)

Returns the value of attribute supported_modes.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def supported_modes
  @supported_modes
end

#supported_presetsObject (readonly)

Returns the value of attribute supported_presets.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def supported_presets
  @supported_presets
end

#supported_swing_modesObject (readonly)

Returns the value of attribute supported_swing_modes.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def supported_swing_modes
  @supported_swing_modes
end

#swing_modeObject (readonly)

Returns the value of attribute swing_mode.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def swing_mode
  @swing_mode
end

#target_humidityObject (readonly)

Returns the value of attribute target_humidity.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def target_humidity
  @target_humidity
end

#target_temperatureObject (readonly)

Returns the value of attribute target_temperature.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def target_temperature
  @target_temperature
end

#target_temperature_highObject (readonly)

Returns the value of attribute target_temperature_high.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def target_temperature_high
  @target_temperature_high
end

#target_temperature_lowObject (readonly)

Returns the value of attribute target_temperature_low.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def target_temperature_low
  @target_temperature_low
end

#temperature_unitObject (readonly)

Returns the value of attribute temperature_unit.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def temperature_unit
  @temperature_unit
end

#visual_humidity_rangeObject (readonly)

Returns the value of attribute visual_humidity_range.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def visual_humidity_range
  @visual_humidity_range
end

#visual_target_temperature_stepObject (readonly)

Returns the value of attribute visual_target_temperature_step.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def visual_target_temperature_step
  @visual_target_temperature_step
end

#visual_temperature_rangeObject (readonly)

Returns the value of attribute visual_temperature_range.



35
36
37
# File 'lib/esphome/entities/climate.rb', line 35

def visual_temperature_range
  @visual_temperature_range
end

Instance Method Details

#action?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'lib/esphome/entities/climate.rb', line 97

def action?
  @supports_action
end

#change_fan_mode(mode) ⇒ Object



203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/esphome/entities/climate.rb', line 203

def change_fan_mode(mode)
  mode = mode.to_sym
  if BASE_FAN_MODES.include?(mode)
    device.send(Api::ClimateCommandRequest.new(key:,
                                               has_fan_mode: true,
                                               fan_mode: :"CLIMATE_FAN_#{mode.to_s.upcase}"))
  else
    device.send(Api::ClimateCommandRequest.new(key:,
                                               has_custom_fan_mode: true,
                                               custom_fan_mode: mode.to_s))
  end
end

#change_mode(mode) ⇒ Object



197
198
199
200
201
# File 'lib/esphome/entities/climate.rb', line 197

def change_mode(mode)
  device.send(Api::ClimateCommandRequest.new(key:,
                                             has_mode: true,
                                             mode: :"CLIMATE_MODE_#{mode.to_s.upcase}"))
end

#change_preset(value) ⇒ Object



245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/esphome/entities/climate.rb', line 245

def change_preset(value)
  value = value.to_sym
  if BASE_PRESETS.include?(value)
    device.send(Api::ClimateCommandRequest.new(key:,
                                               has_preset: true,
                                               preset: :"CLIMATE_PRESET_#{value.to_s.upcase}"))
  else
    device.send(Api::ClimateCommandRequest.new(key:,
                                               has_custom_preset: true,
                                               custom_preset: value.to_s))
  end
end

#change_swing_mode(mode) ⇒ Object



233
234
235
236
237
# File 'lib/esphome/entities/climate.rb', line 233

def change_swing_mode(mode)
  device.send(Api::ClimateCommandRequest.new(key:,
                                             has_swing_mode: true,
                                             swing_mode: :"CLIMATE_SWING_#{mode.to_s.upcase}"))
end

#change_target_humidity(value) ⇒ Object



239
240
241
242
243
# File 'lib/esphome/entities/climate.rb', line 239

def change_target_humidity(value)
  device.send(Api::ClimateCommandRequest.new(key:,
                                             has_target_humidity: true,
                                             target_humidity: value))
end

#change_target_temperature(value = nil, low: nil, high: nil) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/esphome/entities/climate.rb', line 216

def change_target_temperature(value = nil, low: nil, high: nil)
  command = Api::ClimateCommandRequest.new(key:)
  if low
    command.has_target_temperature_low = true
    command.target_temperature_low = low
  end
  if high
    command.has_target_temperature_high = true
    command.target_temperature_high = high
  end
  if value
    command.has_target_temperature = true
    command.target_temperature = value
  end
  device.send(command)
end

#current_humidity?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/esphome/entities/climate.rb', line 101

def current_humidity?
  @supports_current_humidity
end

#current_temperature?Boolean

Returns:

  • (Boolean)


89
90
91
# File 'lib/esphome/entities/climate.rb', line 89

def current_temperature?
  @supports_current_temperature
end

#format_humidity(value) ⇒ Object



187
188
189
190
191
# File 'lib/esphome/entities/climate.rb', line 187

def format_humidity(value)
  return "-" if value.nil?

  format("%.0f %%RH", value)
end

#format_temperature(value) ⇒ Object



181
182
183
184
185
# File 'lib/esphome/entities/climate.rb', line 181

def format_temperature(value)
  return "-" if value.nil?

  format("%.#{temperature_decimals}f #{unit_symbol}", value)
end

#formatted_fan_segmentObject



162
163
164
# File 'lib/esphome/entities/climate.rb', line 162

def formatted_fan_segment
  "fan: #{fan_mode || "-"}"
end

#formatted_preset_segmentObject



170
171
172
# File 'lib/esphome/entities/climate.rb', line 170

def formatted_preset_segment
  preset ? preset.to_s : "<preset>"
end

#formatted_segmentsObject



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/esphome/entities/climate.rb', line 142

def formatted_segments
  segments = [state.nil? ? "-" : state.to_s]
  segments << "(#{action || "-"})" if action?
  segments << "#{format_temperature(current_temperature)} /" if current_temperature?
  if two_point_target_temperature?
    segments << format_temperature(target_temperature_low)
    segments << "-"
    segments << format_temperature(target_temperature_high)
  else
    segments << format_temperature(target_temperature)
  end
  segments << "fan: #{fan_mode || "-"}" unless supported_fan_modes.empty?
  segments << "swing: #{swing_mode || "-"}" unless supported_swing_modes.empty?
  segments << formatted_preset_segment unless supported_presets.empty?
  segments << "#{current_humidity || "-"} %RH" if current_humidity?
  segments << "/" if current_humidity? && target_humidity?
  segments << "#{target_humidity || "-"} %RH" if target_humidity?
  segments
end

#formatted_stateObject



138
139
140
# File 'lib/esphome/entities/climate.rb', line 138

def formatted_state
  formatted_segments.join(" ")
end

#formatted_swing_segmentObject



166
167
168
# File 'lib/esphome/entities/climate.rb', line 166

def formatted_swing_segment
  "swing: #{swing_mode || "-"}"
end

#target_humidity?Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/esphome/entities/climate.rb', line 105

def target_humidity?
  @supports_target_humidity
end

#temperature_decimalsObject



174
175
176
177
178
179
# File 'lib/esphome/entities/climate.rb', line 174

def temperature_decimals
  str = visual_target_temperature_step.to_s
  return 0 unless str.include?(".")

  str.split(".").last.sub(/0+\z/, "").length
end

#two_point_target_temperature?Boolean

Returns:

  • (Boolean)


93
94
95
# File 'lib/esphome/entities/climate.rb', line 93

def two_point_target_temperature?
  @supports_two_point_target_temperature
end

#unit_symbolObject



193
194
195
# File 'lib/esphome/entities/climate.rb', line 193

def unit_symbol
  UNIT_SYMBOLS[temperature_unit]
end

#update(state_response) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/esphome/entities/climate.rb', line 109

def update(state_response)
  @state = state_response.mode[13..].downcase.to_sym
  @current_temperature = state_response.current_temperature if current_temperature?
  if two_point_target_temperature?
    @target_temperature_low = state_response.target_temperature_low
    @target_temperature_high = state_response.target_temperature_high
  else
    @target_temperature = state_response.target_temperature
  end
  @action = state_response.action[15..].downcase.to_sym if action?
  @fan_mode = if state_response.custom_fan_mode.empty?
                state_response.fan_mode[12..].downcase.to_sym
              else
                state_response.custom_fan_mode.downcase.to_sym
              end
  @swing_mode = state_response.swing_mode[14..].downcase.to_sym
  @preset = if !state_response.custom_preset.empty?
              state_response.custom_preset.to_sym
            elsif state_response.unused_legacy_away
              :away
            elsif state_response.preset == :CLIMATE_PRESET_NONE
              nil
            else
              state_response.preset[15..].downcase.to_sym
            end
  @current_humidity = state_response.current_humidity if current_humidity?
  @target_humidity = state_response.target_humidity if target_humidity?
end