class HomieDevice

Create filename for config-data of a HomieDevice depending on default pattern (Homie-<MAC>.yaml) or a given parameter replacing 'Homie'.

Defines a class for storing all attributes of a Homie-device (aka ESP8266 with Homie-Firmware 2.0 (see: github.com/marvinroger/homie).

Attributes

checksum[R]
fw_brand[R]
fw_name[R]
fw_version[R]
mac[R]
upgradable[R]

Public Class Methods

new(mqtt, *fw_list) click to toggle source
# File lib/hodmin/hodmin_tools.rb, line 97
def initialize(mqtt, *fw_list)
  fw_list.flatten!
  startseq = mqtt.select { |t, _m| t.include?('/$homie') }.first.first.split('$').first
  @mac = startseq.split(/\//).last
  mqtt.map! { |t, m| [t.gsub(startseq, ''), m] }
  mhash = Hash[*mqtt.flatten]
  create_attr('homieVersion', mhash['$homie'])
  if mhash['$homie'] > configatron.MAX_HOMIEVERSION
    Log.log.warn "Device #{mac}: Detected new Homie-version (#{mhash['$homie']})"\
    + ' check hodmin for updates'
  end
  mhash.tap { |hs| hs.delete('$homie') }
  mhash.each { |k, v| create_attr(k.to_s, v) }

  # mac only downcase and without separating ':'
  @mac = mac.delete(':').downcase

  # for selecting purposes we need some of our topics in different varnames:
  @checksum = @fw_checksum
  # do we find a higher version of this firmware than installed one?
  @upgradable = fw_list.empty? ? false : upgradable?(fw_name, fw_version, fw_list)
  Log.log.info "Homie-Device detected: mac=#{@mac}, #{online_status}, " \
    + " running #{fw_name}, #{fw_version}, upgr=#{upgradable}"
end

Public Instance Methods

config_yaml_filename_homie(fn) click to toggle source
# File lib/hodmin/hodmin_pull_config.rb, line 34
def config_yaml_filename_homie(fn)
  config_extension = '.yaml'
  if fn.include?('<MAC>')
    fn.gsub(/<MAC>/, mac) + config_extension
  else
    fn.gsub(/[^A-Za-z0-9]/, '') + '-' + mac + config_extension
  end
end
create_attr(name, value) click to toggle source

Helper to create instance variables on the fly:

# File lib/hodmin/hodmin_tools.rb, line 128
def create_attr(name, value)
  # Some topics-names of homie do not fit our needs due to special chars like '/'.
  # ['$fw/name','$fw/version','$fw/checksum']
  # to fix this, replace / delete some chars:
  name = cleanup_instance_var_name(name)
  # do we already have a instance variable with this name?
  name = ensure_individual_instance_name(name, instance_variables)
  # now name should be clean, we create an instancevariable using this name:
  create_method(name.to_sym) { instance_variable_get('@' + name) }
  instance_variable_set('@' + name, value)
end
create_method(name, &block) click to toggle source

Helper to create instance variables on the fly:

# File lib/hodmin/hodmin_tools.rb, line 123
def create_method(name, &block)
  self.class.send(:define_method, name, &block)
end
online?() click to toggle source

Helper to determine status of a device (online/offline). Checks it via reading the online-topic of device at time of creating this object. WARNING: If you use this in a longer running program, this info may be outdated. In this case you should create a method that establishes a connection to your broker and reads the online-topic of this device during execution time.

# File lib/hodmin/hodmin_tools.rb, line 145
def online?
  online.casecmp('true').zero?
end
online_status() click to toggle source

Helper to create a string containing ONLINE or OFFLINE. Gets it via reading the online-topic of the device at time of creating this object. WARNING: If you use this in a longer running program, this info may be outdated. In this case you should create a method that establishes a connection to your broker and reads the online-topic of this device during execution time.

# File lib/hodmin/hodmin_tools.rb, line 154
def online_status
  online? ? 'ONLINE' : 'OFFLINE'
end
push_firmware_to_dev(new_firmware) click to toggle source

Helper to push a firmware-file vai MQTT to our Homie-Device.

# File lib/hodmin/hodmin_tools.rb, line 159
def push_firmware_to_dev(new_firmware)
  bin_file = File.read(new_firmware.file_path)
  md5_bin_file = Digest::MD5.hexdigest(bin_file)
  base_topic = configatron.mqtt.base_topic + mac + '/'
  client = mqtt_connect
  sended = FALSE
  client.publish(base_topic + '$implementation/ota/checksum', md5_bin_file, retain = false)
  sleep 0.1
  client.subscribe(base_topic + '$implementation/ota/status')
  cursor = TTY::Cursor
  puts ' '
  client.get do |_topic, message|
    ms = message
    ms = message.split(/ /).first.strip if message.include?(' ')
    if ms == '206'
      now, ges = message.split(/ /).last.strip.split(/\//).map(&:to_i)
      actual = (now / ges.to_f * 100).round(0)
      print cursor.column(1)
      print "Pushing firmware, #{actual}% done"
    end
    if ms == '304'
      puts '304, file already installed. No action needed. ' + message
      break
    end
    if ms == '403'
      puts '403, OTA disabled:' + message
      break
    end
    if ms == '400'
      puts '400, Bad checksum:' + message
      break
    end
    if ms == '202'
      puts '202, pushing file'
      client.publish(base_topic + '$implementation/ota/firmware', bin_file, retain = false)
      sended = TRUE
    end
    if ms == '200' && sended
      puts "\nFile-md5=#{md5_bin_file} installed, device #{name} is rebooting"
      break
    end
  end
end