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
Public Class Methods
# 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
# 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
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
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
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
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
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