diff --git a/Rakefile b/Rakefile
index 1f4fd9ff6d715ef63c74d56c5eb0ebcb0975d91f..a435c5433139746d6c052f9514c05abf9b1e4b69 100644
--- a/Rakefile
+++ b/Rakefile
@@ -203,7 +203,7 @@ namespace :gen do
 
   namespace :puppet do
 
-    all_puppet_tasks = [:bindg5k, :conmang5k, :dhcpg5k, :kadeployg5k, :lanpowerg5k, :kavlang5k, :network_monitoring, :'refapi-subset']
+    all_puppet_tasks = [:bindg5k, :conmang5k, :dhcpg5k, :kadeployg5k, :lanpowerg5k, :kavlang5k, :kwollectg5k, :network_monitoring, :'refapi-subset']
 
     all_puppet_tasks.each { |t|
       generated_desc = (t == :'refapi-subset') ? 'description' : 'configuration'
diff --git a/lib/refrepo/gen/puppet/kwollectg5k.rb b/lib/refrepo/gen/puppet/kwollectg5k.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c787212a15d79eff0c6f4e71b8a87b3e859d185f
--- /dev/null
+++ b/lib/refrepo/gen/puppet/kwollectg5k.rb
@@ -0,0 +1,67 @@
+require 'refrepo/hash/hash'
+
+def generate_puppet_kwollectg5k(options)
+
+  puts "Writing kwollect configuration files to: #{options[:output_dir]}"
+  puts "Using configuration directory: #{options[:conf_dir]}"
+  puts "For site(s): #{options[:sites].join(', ')}"
+
+  if not options[:conf_dir]
+    options[:conf_dir] = "#{options[:output_dir]}/platforms/production/generators/ipmitools/"
+  end
+  if not Pathname("#{options[:conf_dir]}/console-password.yaml").exist?
+    puts "Warning: No #{options[:conf_dir]}/console-password.yaml file found"
+    credentials = {}
+  else
+    credentials = YAML::load_file("#{options[:conf_dir]}/console-password.yaml")
+  end
+
+  refapi = load_data_hierarchy
+
+  refapi['sites'].each { |site_uid, site|
+
+    next unless options[:sites].include?(site_uid)
+
+    # Metrics configuration for each node
+    site['clusters'].sort.each { |cluster_uid, cluster|
+      cluster['nodes'].each_sort_by_node_uid { |node_uid, node|
+
+        ipmi_credentials = credentials.fetch(site_uid, {}).fetch(cluster_uid, "").sub(" ", ":")
+
+        output = ERB.new(File.read(File.expand_path('templates/kwollect-node.erb', File.dirname(__FILE__))), nil, '-').result(binding)
+        output_file = Pathname("#{options[:output_dir]}//platforms/production/modules/generated/files/grid5000/kwollect/#{site_uid}/#{node_uid}.conf")
+        output_file.dirname.mkpath()
+        File.write(output_file, output)
+      }
+    }
+
+    # Metrics configuration for network device
+    site['network_equipments'].each { |neteq_uid, neteq|
+
+      output = ERB.new(File.read(File.expand_path('templates/kwollect-network.erb', File.dirname(__FILE__))), nil, '-').result(binding)
+      output_file = Pathname("#{options[:output_dir]}//platforms/production/modules/generated/files/grid5000/kwollect/#{site_uid}/#{neteq_uid}.conf")
+      output_file.dirname.mkpath()
+      File.write(output_file, output)
+    }
+
+    # Wattmetre mapping configuration
+    wattmetre_port_per_node = {}
+    site.fetch('pdus', {}).each { |pdu_uid, pdu|
+
+      next if pdu.fetch('metrics', []).none?{|metric| metric['source']['protocol'] == 'wattmetre'}
+
+      pdu.fetch('ports', {}).each {|port, node|
+        if not wattmetre_port_per_node.key?(node)
+          wattmetre_port_per_node[node] = []
+        end
+        wattmetre_port_per_node[node].append("#{pdu_uid}-port#{port}")
+      }
+    }
+    if not wattmetre_port_per_node.empty?
+      output = ERB.new(File.read(File.expand_path('templates/kwollect-wattmetre-mapping.erb', File.dirname(__FILE__))), nil, '-').result(binding)
+      output_file = Pathname("#{options[:output_dir]}//platforms/production/modules/generated/files/grid5000/kwollect-wattmetre/#{site_uid}/wattmetre-mapping.conf")
+      output_file.dirname.mkpath()
+      File.write(output_file, output)
+    end
+  }
+end
diff --git a/lib/refrepo/gen/puppet/templates/kwollect-network.erb b/lib/refrepo/gen/puppet/templates/kwollect-network.erb
new file mode 100644
index 0000000000000000000000000000000000000000..7475b23cb5db0382959cbabe29c7fd9c13044683
--- /dev/null
+++ b/lib/refrepo/gen/puppet/templates/kwollect-network.erb
@@ -0,0 +1,44 @@
+#
+# This file was generated from reference-repository.git
+# Do not edit this file by hand. Your changes will be overwritten.
+#
+
+<%-
+neteq.fetch('metrics', []).each {|metric|
+  next if metric['source']['protocol'] != 'snmp'
+  if metric['source']['id'].include?('%SNMP_IFACE%')
+    neteq['linecards'].each_with_index {|linecard, linecard_uid|
+      linecard.fetch('ports', []).each_with_index {|lport, lport_uid|
+        next if lport.empty?
+        lport_uid += 12
+        port_uid = neteq['linecards'].length > 1 ? "#{linecard_uid}_#{lport_uid}" : lport_uid
+        port_name = linecard["snmp_pattern"].sub("%LINECARD%",linecard_uid.to_s).sub("%PORT%",lport_uid.to_s)
+        # TODO: Handle secondary interface
+        port_node = lport['uid']
+-%>
+- name: <%= metric['name'] %>
+  device_id: <%= neteq_uid %>-port-<%= port_uid %>
+  device_alias: <%= port_node %>
+  url: snmp://<%= neteq.fetch('snmp_community', 'public')%>@<%= neteq_uid %>.<%= site_uid %>.grid5000.fr/<%= metric['source']['id'].sub('%SNMP_IFACE%',  "{{ #{port_name} }}") %>
+  update_every: <%= metric['period'] > 0 ? metric['period'] : metric['optional_period'] %>
+<%- if metric['period'] == 0 -%>
+  optional: true
+<%- end -%>
+
+<%-
+      }
+    }
+  else
+-%>
+- name: <%= metric['name'] %>
+  device_id: <%= neteq_uid %>
+  url: snmp://<%= neteq.fetch('snmp_community', 'public')%>@<%= neteq_uid %>.<%= site_uid %>.grid5000.fr/<%= metric['source']['id'] %>
+  update_every: <%= metric['period'] > 0 ? metric['period'] : metric['optional_period'] %>
+<%- if metric['period'] == 0 -%>
+  optional: true
+<%- end -%>
+
+<%-
+  end
+}
+-%>
diff --git a/lib/refrepo/gen/puppet/templates/kwollect-node.erb b/lib/refrepo/gen/puppet/templates/kwollect-node.erb
new file mode 100644
index 0000000000000000000000000000000000000000..77f45249745720764cc9e256c14391173839a8dc
--- /dev/null
+++ b/lib/refrepo/gen/puppet/templates/kwollect-node.erb
@@ -0,0 +1,32 @@
+#
+# This file was generated from reference-repository.git
+# Do not edit this file by hand. Your changes will be overwritten.
+#
+
+<%-
+cluster.fetch('metrics', []).each {|metric|
+  next if metric['source']['protocol'] == "wattmetre"
+  next if metric['source']['protocol'] == "network_equipment"
+
+  if metric['source']['protocol'] == "ipmisensor"
+    auth = ipmi_credentials+"@"
+  elsif metric['source']['protocol'] == "snmp"
+    auth = "public@"
+  else
+    auth = ""
+  end
+
+-%>
+- name: <%= metric['name'] %>
+  device_id: <%= node_uid %>
+  url: <%= metric['source']['protocol'] %>://<%= auth %><%= node_uid %>-bmc.<%= site_uid %>.grid5000.fr/<%= metric['source']['id'] %>
+  device_alias: <%= node_uid %>-bmc
+  update_every: <%= metric['period'] > 0 ? metric['period'] : metric['optional_period'] %>
+<%- if metric['period'] == 0 -%>
+  optional: true
+<%- end -%>
+
+<%-
+}
+-%>
+
diff --git a/lib/refrepo/gen/puppet/templates/kwollect-wattmetre-mapping.erb b/lib/refrepo/gen/puppet/templates/kwollect-wattmetre-mapping.erb
new file mode 100644
index 0000000000000000000000000000000000000000..e3f55d7f8a4a3a042fdd14e21101b7c952c304ce
--- /dev/null
+++ b/lib/refrepo/gen/puppet/templates/kwollect-wattmetre-mapping.erb
@@ -0,0 +1,14 @@
+#
+# This file was generated from reference-repository.git
+# Do not edit this file by hand. Your changes will be overwritten.
+#
+
+<%-
+wattmetre_port_per_node.each {|node, ports|
+-%>
+<%= node %>: [<%= ports.join(',') %>]
+<%-
+}
+-%>
+
+
diff --git a/lib/refrepo/valid/input/schemas/schema-cluster.yaml b/lib/refrepo/valid/input/schemas/schema-cluster.yaml
index 0d4d7128e52a11959fb96311366f6406dad81046..a6ff96d80d3469f01e6f4a12428cbe32cd21dac6 100644
--- a/lib/refrepo/valid/input/schemas/schema-cluster.yaml
+++ b/lib/refrepo/valid/input/schemas/schema-cluster.yaml
@@ -5,3 +5,4 @@ created_at: required # string or date ?
 kavlan: boolean
 queues: array
 priority: optional_string
+metrics: optional_array
diff --git a/lib/refrepo/valid/input/schemas/schema-network_equipments.yaml b/lib/refrepo/valid/input/schemas/schema-network_equipments.yaml
index 0521c46128ca32a15fee1221a53d56551e65818d..d7cd0b6ad3f69924a83388a45c47870be2b7e622 100644
--- a/lib/refrepo/valid/input/schemas/schema-network_equipments.yaml
+++ b/lib/refrepo/valid/input/schemas/schema-network_equipments.yaml
@@ -56,3 +56,4 @@ channels:
       uid: string
       kind: string
       rate: integer
+metrics: optional_array
diff --git a/lib/refrepo/valid/input/schemas/schema-site.yaml b/lib/refrepo/valid/input/schemas/schema-site.yaml
index 789dcd07c4ebed05f93aba661d10ac985f9bd42a..d87dc60e41acaadef63b43cfaf122dcdad62190d 100644
--- a/lib/refrepo/valid/input/schemas/schema-site.yaml
+++ b/lib/refrepo/valid/input/schemas/schema-site.yaml
@@ -71,6 +71,7 @@ pdus:
       mac: optional_string
       vendor: optional_string
       model: optional_string
+      metrics: optional_array
       sensors:
         <array>:
           power: