diff --git a/files/enoc_pdu_snmp2node_exporter.py b/files/enoc_pdu_snmp2node_exporter.py
new file mode 100644
index 0000000000000000000000000000000000000000..601dbc203f192164bc8456fee64e122a0030016b
--- /dev/null
+++ b/files/enoc_pdu_snmp2node_exporter.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+import ast
+import os
+import subprocess
+from pathlib import Path
+
+
+def process_kv(k, v):
+    if v.startswith('"') and v.endswith('"'):
+        return k, ast.literal_eval(v)
+    elif 'Current' in k or 'Energy' in k:
+        # The energy and current values received from the PDUs are multiplied by 10
+        return k, int(v)/10
+    return k, int(v)
+
+
+def walk(agent):
+    p = subprocess.run(
+        [
+            'snmpwalk', '-O', 'Q',
+            '-r', '1',
+            '-t', '1',
+            '-m', 'IPPDU-MIB',
+            '-v', '1',
+            '-c', 'public',
+            agent,
+            '1.3.6.1.4.1.30966.10.3'
+        ],
+        stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, encoding='utf-8'
+    )
+    data = [process_kv(*line.split(' = ', 1)) for line in p.stdout.strip().splitlines() if '=' in line]
+    return {k: v for k, v in data}
+
+
+def get_metrics(agent):
+    d = walk(agent)
+
+    lines = []
+
+    for phase in ['A', 'B', 'C']:
+        labels = {'phase': phase, 'agent': agent}
+        labels_str = '{' + ','.join(f'{k}="{v}"' for k, v in labels.items()) + '}'
+
+        try:
+            voltage = d[f'IPPDU-MIB::mVoltage{phase}.0']
+            lines.append(f'pdu_voltage{labels_str} {voltage}')
+        except KeyError:
+            pass
+
+        try:
+            current = d[f'IPPDU-MIB::mCurrent{phase}.0']
+            lines.append(f'pdu_current{labels_str} {current}')
+        except KeyError:
+            pass
+
+        try:
+            # convert KWh to Joules, the preferred unit in prometheus
+            energy = d[f'IPPDU-MIB::mEnergy{phase}.0'] * 3_600_000
+            lines.append(f'pdu_joules_total{labels_str} {energy}')
+        except KeyError:
+            pass
+
+    return lines
+
+
+def main():
+    with open('/usr/local/etc/enoc_pdu_snmp2node_exporter.hosts', 'r') as f:
+        hosts = f.read().strip().splitlines()
+
+    tmp_file = Path(f'/var/lib/prometheus-dropzone/pdu.prom.{os.getpid()}')
+
+    with tmp_file.open('w') as f:
+        for h in hosts:
+            f.write('\n'.join(get_metrics(h)) + '\n')
+
+    tmp_file.rename(tmp_file.with_name('pdu.prom'))
+
+
+if __name__ == '__main__':
+    main()
diff --git a/files/ip2017.MIB b/files/ip2017.MIB
new file mode 100644
index 0000000000000000000000000000000000000000..623391b978cb3e38b491a6c82f14c928a923fc6c
--- /dev/null
+++ b/files/ip2017.MIB
@@ -0,0 +1,454 @@
+IPPDU-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+    enterprises, Counter,
+    TimeTicks, Gauge                FROM RFC1155-SMI
+    OBJECT-TYPE                     FROM RFC-1212
+    sysUpTime, DisplayString		  FROM RFC1213-MIB
+TRAP-TYPE                           FROM RFC-1215;
+
+clever OBJECT IDENTIFIER ::= { enterprises 30966 }
+ip-PDU OBJECT IDENTIFIER ::= { clever 10 }
+ipPDU OBJECT IDENTIFIER ::= { ip-PDU 3 }
+deviceInfo OBJECT IDENTIFIER ::= { ipPDU 1 }
+statusInfo OBJECT IDENTIFIER ::= { ipPDU 2 }
+
+DeviceName OBJECT-TYPE
+    SYNTAX DisplayString (SIZE (255))
+    ACCESS read-write
+    STATUS optional
+    DESCRIPTION
+            "device name."
+    ::= { deviceInfo 1 }
+
+mVoltageA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Line 1 total votage."
+    ::= { statusInfo 1 }
+
+mVoltageB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Line 2 total votage."
+    ::= { statusInfo 2 }    
+
+mVoltageC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Line 3 total votage."
+    ::= { statusInfo 3 }
+
+mCurrentA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Line 1 total current.Magnified 10 times."
+    ::= { statusInfo 4 }
+
+mCurrentB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Line 2 total current.Magnified 10 times."
+    ::= { statusInfo 5 }    
+
+mCurrentC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Line 3 total current.Magnified 10 times."
+    ::= { statusInfo 6 }
+    
+mEnergyA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Line 1 energy .Magnified 10 times."
+    ::= { statusInfo 7 }
+mEnergyB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Line 2 energy .Magnified 10 times."
+    ::= { statusInfo 8 }
+mEnergyC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Line 3 energy .Magnified 10 times."
+    ::= { statusInfo 9 }  
+mTemperature OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Temperature"
+    ::= { statusInfo 10 }
+mHumidity OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "Master Humidity"
+    ::= { statusInfo 11 }    
+    
+    
+sOneVoltageA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne Line 1 total votage."
+    ::= { statusInfo 12 }
+
+sOneVoltageB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne Line 2 total votage."
+    ::= { statusInfo 13 }    
+
+sOneVoltageC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne Line 3 total votage."
+    ::= { statusInfo 14 }
+
+sOneCurrentA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne Line 1 total current.Magnified 10 times."
+    ::= { statusInfo 15 }
+
+sOneCurrentB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne Line 2 total current.Magnified 10 times."
+    ::= { statusInfo 16 }    
+
+sOneCurrentC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne Line 3 total current.Magnified 10 times."
+    ::= { statusInfo 17 }
+    
+sOneEnergyA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne Line 1 energy .Magnified 10 times."
+    ::= { statusInfo 18 }
+sOneEnergyB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne Line 2 energy .Magnified 10 times."
+    ::= { statusInfo 19 }
+sOneEnergyC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne Line 3 energy .Magnified 10 times."
+    ::= { statusInfo 20 } 
+sOneTem OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne  Temperature"
+    ::= { statusInfo 21 }
+sOneHum OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveOne  Humidity"
+    ::= { statusInfo 22 }          
+    
+            
+sTwoVoltageA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo Line 1 total votage."
+    ::= { statusInfo 23 }
+
+sTwoVoltageB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo Line 2 total votage."
+    ::= { statusInfo 24 }    
+
+sTwoVoltageC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo Line 3 total votage."
+    ::= { statusInfo 25 }
+
+sTwoCurrentA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo Line 1 total current.Magnified 10 times."
+    ::= { statusInfo 26 }
+
+sTwoCurrentB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo Line 2 total current.Magnified 10 times."
+    ::= { statusInfo 27 }    
+
+sTwoCurrentC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo Line 3 total current.Magnified 10 times."
+    ::= { statusInfo 28 }
+    
+sTwoEnergyA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo Line 1 energy .Magnified 10 times."
+    ::= { statusInfo 29 }
+sTwoEnergyB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo Line 2 energy .Magnified 10 times."
+    ::= { statusInfo 30 }
+sTwoEnergyC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo Line 3 energy .Magnified 10 times."
+    ::= { statusInfo 31 } 
+sTwoTem OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo  Temperature"
+    ::= { statusInfo 32 }
+sTwoHum OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveTwo  Humidity"
+    ::= { statusInfo 33 }       
+      
+      
+      
+sThreeVoltageA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree Line 1 total votage."
+    ::= { statusInfo 34 }
+
+sThreeVoltageB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree Line 2 total votage."
+    ::= { statusInfo 35 }    
+
+sThreeVoltageC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree Line 3 total votage."
+    ::= { statusInfo 36 }
+
+sThreeCurrentA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree Line 1 total current.Magnified 10 times."
+    ::= { statusInfo 37 }
+
+sThreeCurrentB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree Line 2 total current.Magnified 10 times."
+    ::= { statusInfo 38 }    
+
+sThreeCurrentC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree Line 3 total current.Magnified 10 times."
+    ::= { statusInfo 39 }
+    
+sThreeEnergyA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree Line 1 energy .Magnified 10 times."
+    ::= { statusInfo 40 }
+sThreeEnergyB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree Line 2 energy .Magnified 10 times."
+    ::= { statusInfo 41 }
+sThreeEnergyC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree Line 3 energy .Magnified 10 times."
+    ::= { statusInfo 42 } 
+sThreeTem OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree  Temperature"
+    ::= { statusInfo 43 }
+sThreeHum OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveThree  Humidity"
+    ::= { statusInfo 44 }            
+
+
+sFourVoltageA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour Line 1 total votage."
+    ::= { statusInfo 45 }
+
+sFourVoltageB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour Line 2 total votage."
+    ::= { statusInfo 46 }    
+
+sFourVoltageC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour Line 3 total votage."
+    ::= { statusInfo 47 }
+
+sFourCurrentA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour Line 1 total current.Magnified 10 times."
+    ::= { statusInfo 48 }
+
+sFourCurrentB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour Line 2 total current.Magnified 10 times."
+    ::= { statusInfo 49 }    
+
+sFourCurrentC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour Line 3 total current.Magnified 10 times."
+    ::= { statusInfo 50 }
+    
+sFourEnergyA OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour Line 1 energy .Magnified 10 times."
+    ::= { statusInfo 51 }
+sFourEnergyB OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour Line 2 energy .Magnified 10 times."
+    ::= { statusInfo 52 }
+sFourEnergyC OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour Line 3 energy .Magnified 10 times."
+    ::= { statusInfo 53 } 
+sFourTem OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour  Temperature"
+    ::= { statusInfo 54 }
+sFourHum OBJECT-TYPE
+    SYNTAX INTEGER (0..65535)
+    ACCESS read-only
+    STATUS optional
+    DESCRIPTION
+            "SlaveFour  Humidity"
+    ::= { statusInfo 55 }        
+
+
+
+
+
+
+END
diff --git a/manifests/init.pp b/manifests/init.pp
index 234351bce17e046b09ad0880b47ca260b93e92a1..c709e88f9535f9692fba25636fb58c8c35050efd 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -32,4 +32,81 @@ class orwell {
     user    => 'root',
     minute  => '*/2',
   }
+
+  include orwell::enoc_pdu_snmp
+}
+
+class orwell::enoc_pdu_snmp {
+  package { 'net-snmp-utils':
+    ensure => installed,
+  }
+  package { 'python3':
+    ensure => installed,
+  }
+
+  file { '/root/.snmp/':
+    ensure => directory,
+  }
+  -> file { '/root/.snmp/mibs/':
+    ensure => directory,
+  }
+  -> file { '/root/.snmp/mibs/ip2017.MIB':
+    ensure => file,
+    source => 'puppet:///modules/orwell/ip2017.MIB',
+  }
+
+  file { '/usr/local/sbin/enoc_pdu_snmp2node_exporter.py':
+    ensure => file,
+    source => 'puppet:///modules/orwell/enoc_pdu_snmp2node_exporter.py',
+    mode   => '500',
+  }
+
+  $hosts = [
+    'pdu-r1-1.mgmt',
+    'pdu-r1-2.mgmt',
+    'pdu-r2-1.mgmt',
+    'pdu-r2-2.mgmt',
+    'pdu-r3-1.mgmt',
+    'pdu-r3-2.mgmt',
+    'pdu-r4-1.mgmt',
+    'pdu-r4-2.mgmt',
+    'pdu-r5-1.mgmt',
+    'pdu-r5-2.mgmt',
+    'pdu-r6-1.mgmt',
+    'pdu-r6-2.mgmt',
+    'pdu-r7-1.mgmt',
+    'pdu-r7-2.mgmt',
+    'pdu-r8-1.mgmt',
+    'pdu-r8-2.mgmt',
+    'pdu-r9-1.mgmt',
+    'pdu-r9-2.mgmt',
+    'pdu-r10-1.mgmt',
+    'pdu-r10-2.mgmt',
+    'pdu-r11-1.mgmt',
+    'pdu-r11-2.mgmt',
+  ]
+
+  file { '/usr/local/etc/enoc_pdu_snmp2node_exporter.hosts':
+    ensure  => file,
+    content => ($hosts + ['']).join("\n")
+  }
+
+  $timer_content = @(EOS)
+[Timer]
+OnCalendar=*:*:0/10
+EOS
+
+  $service_content = @(EOS)
+[Service]
+User=root
+Type=oneshot
+ExecStart=/usr/local/sbin/enoc_pdu_snmp2node_exporter.py
+EOS
+
+  systemd::timer { 'enoc_pdu_snmp2node_exporter.timer':
+    active          => true,
+    enable          => true,
+    timer_content   => $timer_content,
+    service_content => $service_content,
+  }
 }