module MQTT::HomeAssistant
Constants
- DEVICE_CLASSES
- ENTITY_CATEGORIES
- ON_COMMAND_TYPES
- STATE_CLASSES
- VERSION
Public Class Methods
publish_binary_sensor( property, device_class: nil, expire_after: nil, force_update: false, off_delay: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil )
click to toggle source
@param property [MQTT::Homie::Property] A Homie
property object of datatype :boolean
# File lib/mqtt/home_assistant.rb, line 82 def publish_binary_sensor( property, device_class: nil, expire_after: nil, force_update: false, off_delay: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil ) raise ArgumentError, "Homie property must be a boolean" unless property.datatype == :boolean if device_class && !DEVICE_CLASSES[:binary_sensor].include?(device_class) raise ArgumentError, "Unrecognized device_class #{device_class.inspect}" end config = base_config(property.device, property.full_name, device_class: device_class, device: device, entity_category: entity_category, icon: icon) .merge({ payload_off: "false", payload_on: "true", unique_id: "#{property.device.id}_#{property.node.id}_#{property.id}", state_topic: property.topic }) config[:expire_after] = expire_after if expire_after config[:force_update] = true if force_update config[:off_delay] = off_delay if off_delay publish(property.mqtt, "binary_sensor", config, discovery_prefix: discovery_prefix) end
publish_climate( action_property: nil, aux_property: nil, away_mode_property: nil, current_temperature_property: nil, fan_mode_property: nil, mode_property: nil, hold_property: nil, power_property: nil, swing_mode_property: nil, temperature_property: nil, temperature_high_property: nil, temperature_low_property: nil, name: nil, id: nil, precision: nil, temp_step: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil, templates: {} )
click to toggle source
# File lib/mqtt/home_assistant.rb, line 118 def publish_climate( action_property: nil, aux_property: nil, away_mode_property: nil, current_temperature_property: nil, fan_mode_property: nil, mode_property: nil, hold_property: nil, power_property: nil, swing_mode_property: nil, temperature_property: nil, temperature_high_property: nil, temperature_low_property: nil, name: nil, id: nil, precision: nil, temp_step: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil, templates: {} ) properties = { action: action_property, aux: aux_property, away_mode: away_mode_property, current_temperature: current_temperature_property, fan_mode: fan_mode_property, mode: mode_property, hold: hold_property, power: power_property, swing_mode: swing_mode_property, temperature: temperature_property, temperature_high: temperature_high_property, temperature_low: temperature_low_property }.compact raise ArgumentError, "At least one property must be specified" if properties.empty? raise ArgumentError, "Power property must be a boolean" if power_property && power_property.datatype != :boolean node = properties.first.last.node config = base_config(node.device, name || node.full_name, device: device, entity_category: entity_category, icon: icon) config[:unique_id] = "#{node.device.id}_#{id || node.id}" read_only_props = %i[action current_temperature] properties.each do |prefix, property| add_property(config, property, prefix, templates: templates, read_only: read_only_props.include?(prefix)) end temp_properties = [ temperature_property, temperature_high_property, temperature_low_property ].compact unless (temp_ranges = temp_properties.map(&:range).compact).empty? config[:min_temp] = temp_ranges.map(&:begin).min config[:max_temp] = temp_ranges.map(&:end).max end temperature_unit = temp_properties.map(&:unit).compact.first config[:temperature_unit] = temperature_unit[-1] if temperature_unit { nil => mode_property, :fan => fan_mode_property, :hold => hold_property, :swing => swing_mode_property }.compact.each do |prefix, property| valid_set = %w[auto off cool heat dry fan_only] if prefix.nil? add_enum(config, property, prefix, valid_set) end config[:precision] = precision if precision config[:temp_step] = temp_step if temp_step if power_property config[:payload_on] = "true" config[:payload_off] = "false" end publish(node.mqtt, "climate", config, discovery_prefix: discovery_prefix) end
publish_fan( property, oscillation_property: nil, percentage_property: nil, preset_mode_property: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil )
click to toggle source
# File lib/mqtt/home_assistant.rb, line 201 def publish_fan( property, oscillation_property: nil, percentage_property: nil, preset_mode_property: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil ) config = base_config(property.device, name || property.node.full_name, device: device, device_class: device_class, entity_category: entity_category, icon: icon, templates: {}) add_property(config, oscillation_property, :oscillation_property, templates: templates) add_property(config, percentage_property, :percentage, templates: templates) if percentage_property&.range config[:speed_range_min] = percentage_property.range.begin config[:speed_range_max] = percentage_property.range.end end add_property(config, preset_mode_property, :preset, templates: templates) add_enum(config, preset_mode_property, :preset) publish(node.mqtt, "fan", config, discovery_prefix: discovery_prefix) end
publish_humidifier( property, device_class:, target_property:, mode_property: nil, name: nil, id: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil )
click to toggle source
# File lib/mqtt/home_assistant.rb, line 231 def publish_humidifier( property, device_class:, target_property:, mode_property: nil, name: nil, id: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil ) raise ArgumentError, "Homie property must be a boolean" unless property.datatype == :boolean unless DEVICE_CLASSES[:humidifier].include?(device_class) raise ArgumentError, "Unrecognized device_class #{device_class.inspect}" end config = base_config(property.device, name || property.node.full_name, device: device, device_class: device_class, entity_category: entity_category, icon: icon) .merge({ command_topic: "#{property.topic}/set", target_humidity_command_topic: "#{target_property.topic}/set", payload_off: "false", payload_on: "true", unique_id: "#{property.device.id}_#{id || property.node.id}" }) add_property(config, property) add_property(config, target_property, :target_humidity) if (range = target_property.range) config[:min_humidity] = range.begin config[:max_humidity] = range.end end add_property(config, mode_property, :mode) add_enum(config, mode_property) publish(property.mqtt, "humidifier", config, discovery_prefix: discovery_prefix) end
publish_light( property = nil, brightness_property: nil, color_mode_property: nil, color_temp_property: nil, effect_property: nil, hs_property: nil, rgb_property: nil, white_property: nil, xy_property: nil, on_command_type: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil, templates: {} )
click to toggle source
‘default` schema only for now
# File lib/mqtt/home_assistant.rb, line 276 def publish_light( property = nil, brightness_property: nil, color_mode_property: nil, color_temp_property: nil, effect_property: nil, hs_property: nil, rgb_property: nil, white_property: nil, xy_property: nil, on_command_type: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil, templates: {} ) if on_command_type && !ON_COMMAND_TYPES.include?(on_command_type) raise ArgumentError, "Invalid on_command_type #{on_command_type.inspect}" end # automatically infer a brightness-only light and adjust config if brightness_property && property.nil? property = brightness_property on_command_type = :brightness end config = base_config(property.device, property.full_name, device: device, entity_category: entity_category, icon: icon) config[:unique_id] = "#{property.device.id}_#{property.node.id}_#{property.id}" add_property(config, property) case property.datatype when :boolean config[:payload_off] = "false" config[:payload_on] = "true" when :integer config[:payload_off] = "0" when :float config[:payload_off] = "0.0" end add_property(config, brightness_property, :brightness, templates: templates) config[:brightness_scale] = brightness_property.range.end if brightness_property&.range add_property(config, color_mode_property, :color_mode, templates: templates) add_property(config, color_temp_property, :color_temp, templates: templates) if color_temp_property&.range && color_temp_property.unit == "mired" config[:min_mireds] = color_temp_property.range.begin config[:max_mireds] = color_temp_property.range.end end add_property(config, effect_property, :effect, templates: templates) config[:effect_list] = effect_property.range if effect_property&.datatype == :enum add_property(config, hs_property, :hs, templates: templates) add_property(config, rgb_property, :rgb, templates: templates) add_property(config, white_property, :white, templates: templates) config[:white_scale] = white_property.range.end if white_property&.range add_property(config, xy_property, :xy, templates: templates) config[:on_command_type] = on_command_type if on_command_type publish(property.mqtt, "light", config, discovery_prefix: discovery_prefix) end
publish_number( property, step: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil )
click to toggle source
# File lib/mqtt/home_assistant.rb, line 340 def publish_number( property, step: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil ) raise ArgumentError, "Homie property must be an integer or a float" unless %i[integer float].include?(property.datatype) config = base_config(property.device, property.full_name, device: device, entity_category: entity_category, icon: icon) config[:unique_id] = "#{property.device.id}_#{property.node.id}_#{property.id}" add_property(config, property) config[:unit_of_measurement] = property.unit if property.unit if property.range config[:min] = property.range.begin config[:max] = property.range.end end config[:step] = step if step publish(property.mqtt, "number", config, discovery_prefix: discovery_prefix) end
publish_scene( property, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil )
click to toggle source
# File lib/mqtt/home_assistant.rb, line 369 def publish_scene( property, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil ) unless property.datatype == :enum && property.range.length == 1 raise ArgumentError, "Homie property must be an enum with a single value" end config = base_config(property.device, property.full_name, device: device, entity_category: entity_category, icon: icon) config[:unique_id] = "#{property.device.id}_#{property.node.id}_#{property.id}" add_property(config, property) config[:payload_on] = property.range.first publish(property.mqtt, "scene", config, discovery_prefix: discovery_prefix) end
publish_select( property, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil )
click to toggle source
# File lib/mqtt/home_assistant.rb, line 393 def publish_select( property, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil ) raise ArgumentError, "Homie property must be an enum" unless property.datatype == :enum raise ArgumentError, "Homie property must be settable" unless property.settable? config = base_config(property.device, property.full_name, device: device, entity_category: entity_category, icon: icon) config[:unique_id] = "#{property.device.id}_#{property.node.id}_#{property.id}" add_property(config, property) config[:options] = property.range publish(property.mqtt, "select", config, discovery_prefix: discovery_prefix) end
publish_sensor( property, device_class: nil, expire_after: nil, force_update: false, state_class: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil )
click to toggle source
@param property [MQTT::Homie::Property] A Homie
property object
# File lib/mqtt/home_assistant.rb, line 417 def publish_sensor( property, device_class: nil, expire_after: nil, force_update: false, state_class: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil ) if device_class && !DEVICE_CLASSES[:sensor].include?(device_class) raise ArgumentError, "Unrecognized device_class #{device_class.inspect}" end if state_class && !STATE_CLASSES.include?(state_class) raise ArgumentError, "Unrecognized state_class #{state_class.inspect}" end config = base_config(property.device, property.full_name, device: device, device_class: device_class, entity_category: entity_category, icon: icon) .merge({ unique_id: "#{property.device.id}_#{property.node.id}_#{property.id}", state_topic: property.topic }) config[:state_class] = state_class if state_class config[:expire_after] = expire_after if expire_after config[:force_update] = true if force_update config[:unit_of_measurement] = property.unit if property.unit publish(property.mqtt, "sensor", config, discovery_prefix: discovery_prefix) end
publish_switch(property, device_class: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil)
click to toggle source
@param property [MQTT::Homie::Property] A Homie
property object of datatype :boolean
# File lib/mqtt/home_assistant.rb, line 455 def publish_switch(property, device_class: nil, device: nil, discovery_prefix: nil, entity_category: nil, icon: nil) raise ArgumentError, "Homie property must be a boolean" unless property.datatype == :boolean config = base_config(property.device, property.full_name, device: device, device_class: device_class, entity_category: entity_category, icon: icon) .merge({ unique_id: "#{property.device.id}_#{property.node.id}_#{property.id}", payload_off: "false", payload_on: "true" }) add_property(config, property) publish(property.mqtt, "switch", config, discovery_prefix: discovery_prefix) end
Private Class Methods
add_enum(config, property, prefix = nil, valid_set = nil)
click to toggle source
# File lib/mqtt/home_assistant.rb, line 495 def add_enum(config, property, prefix = nil, valid_set = nil) prefix = "#{prefix}_" if prefix return unless property&.datatype == :enum modes = property.range modes &= valid_set if valid_set config[:"#{prefix}modes"] = modes end
add_property(config, property, prefix = nil, templates: {}, read_only: false)
click to toggle source
# File lib/mqtt/home_assistant.rb, line 482 def add_property(config, property, prefix = nil, templates: {}, read_only: false) return unless property prefix = "#{prefix}_" if prefix state_prefix = "state_" unless read_only config[:"#{prefix}#{state_prefix}topic"] = property.topic if property.retained? if !read_only && property.settable? config[:"#{prefix}command_topic"] = "#{property.topic}/set" config[:"#{prefix}command_template"] = "{{ value | round(0) }}" if property.datatype == :integer end config.merge!(templates.slice(:"#{prefix}template", :"#{prefix}command_template")) end
base_config(homie_device, name, device:, entity_category:, icon:, device_class: nil)
click to toggle source
# File lib/mqtt/home_assistant.rb, line 505 def base_config(homie_device, name, device:, entity_category:, icon:, device_class: nil) if entity_category && !ENTITY_CATEGORIES.include?(entity_category) raise ArgumentError, "Unrecognized entity_category #{entity_category.inspect}" end config = { name: name, availability_topic: "#{homie_device.topic}/$state", payload_available: "ready", payload_not_available: "lost", qos: 1 } config[:device_class] = device_class if device_class config[:entity_category] = entity_category if entity_category config[:icon] = icon if icon device = device&.dup || {} device[:name] ||= homie_device.name device[:sw_version] ||= MQTT::Homie::Device::VERSION device[:identifiers] ||= homie_device.id unless device[:connections] config[:device] = device config end
publish(mqtt, component, config, discovery_prefix:)
click to toggle source
# File lib/mqtt/home_assistant.rb, line 535 def publish(mqtt, component, config, discovery_prefix:) mqtt.publish("#{discovery_prefix || "homeassistant"}/#{component}/#{config[:unique_id]}/config", config.to_json, retain: true, qos: 1) end