Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python3 -tt
- import configparser
- import os, serial, logging, re, json, datetime
- import sys, time
- import httplib2
- from daemon import Daemon
- from array import array
- logging.basicConfig(filename='p1meter.log', level=logging.INFO)
- log = logging.getLogger(__name__)
- # DSMR interesting codes
- list_of_interesting_codes = {
- '1-0:1.8.1': 'Meter Reading electricity delivered to client (Tariff 1) in kWh',
- '1-0:1.8.2': 'Meter Reading electricity delivered to client (Tariff 2) in kWh',
- '1-0:2.8.1': 'Meter Reading electricity delivered by dient (Tariff 1) in kWh',
- '1-0:2.8.2': 'Meter Reading electricity delivered by client (Tariff 2) in kWh',
- '0-0:96.14.0': 'Tariff indicator electricity',
- '1-0:1.7.0': 'Actual electricity power delivered (+P) in kW',
- '1-0:2.7.0': 'Actual electricity power received (-P) in kW',
- '0-0:17.0.0': 'The actual threshold electricity in kW',
- '0-0:96.3.10': 'Switch position electricity',
- '0-0:96.7.21': 'Number of power failures in any phase',
- '0-0:96.7.9': 'Number of long power failures in any phase',
- '1-0:32.32.0': 'Number of voltage sags in phase L1',
- '1-0:52.32.0': 'Number of voltage sags in phase L2',
- '1-0:72:32.0': 'Number of voltage sags in phase L3',
- '1-0:32.36.0': 'Number of voltage swells in phase L1',
- '1-0:52.36.0': 'Number of voltage swells in phase L2',
- '1-0:72.36.0': 'Number of voltage swells in phase L3',
- '1-0:31.7.0': 'Instantaneous current L1 in A',
- '1-0:51.7.0': 'Instantaneous current L2 in A',
- '1-0:71.7.0': 'Instantaneous current L3 in A',
- '1-0:21.7.0': 'Instantaneous active power L1 (+P) in kW',
- '1-0:41.7.0': 'Instantaneous active power L2 (+P) in kW',
- '1-0:61.7.0': 'Instantaneous active power L3 (+P) in kW',
- '1-0:22.7.0': 'Instantaneous active power L1 (-P) in kW',
- '1-0:42.7.0': 'Instantaneous active power L2 (-P) in kW',
- '1-0:62.7.0': 'Instantaneous active power L3 (-P) in kW'
- }
- class MyDaemon(Daemon):
- def run(self):
- config = configparser.RawConfigParser()
- config.read('/home/p1meter/p1meter/p1meter.conf')
- baudrate = config.getint("meter", "baudrate") ## 115200
- bytesize = config.getint("meter", "bytesize") ## 8
- parity = serial.PARITY_NONE;
- stopbits = config.getint("meter", "stopbits") ## 1
- xonoff = config.getboolean("meter", "xonoff") ## false
- timeout = config.getint("meter", "timeout") ## 10
- port = config.get("meter", "port")
- lastLogAt = datetime.datetime.now()
- usageArray = array('f')
- returnArray = array('f')
- p1 = {}
- log.debug('Open serial connect to {} with: {}'.format(port, ', '.join('{}={}'.format(key, value) for key, value in config.items())))
- try:
- self.serial = serial.Serial()
- self.serial.baudrate = baudrate
- self.serial.bytesize = bytesize
- self.serial.parity = parity
- self.serial.stopbits = stopbits
- self.serial.xonxoff = xonoff
- self.serial.timeout = timeout
- self.serial.port = port
- self.serial.open()
- except (serial.SerialException, OSError) as e:
- log.error(e)
- sys.exit ("Fout bij het openen van poort %s. " % self.serial.name)
- self.serial.close()
- else:
- self.serial.setRTS(False)
- self.port = self.serial.name
- log.info('New serial connection opened to %s', self.port)
- while True:
- try:
- readAt = datetime.datetime.now()
- if (readAt - lastLogAt).total_seconds() >= 60:
- e = {}
- e['read_at'] = p1['timestamp']
- e['usage_1'] = p1['kwh_low_usage']
- e['return_1'] = p1['kwh_low_return']
- e['usage_2'] = p1['kwh_high_usage']
- e['return_2'] = p1['kwh_high_return']
- e['usage'] = sum(usageArray) / len(usageArray)
- e['return'] = sum(returnArray) / len(returnArray)
- e['current_L1'] = p1['current_L1']
- e['current_L2'] = p1['current_L2']
- e['current_L3'] = p1['current_L3']
- e['usage_L1'] = p1['usage_L1']
- e['usage_L2'] = p1['usage_L2']
- e['usage_L3'] = p1['usage_L3']
- e['return_L1'] = p1['return_L1']
- e['return_L2'] = p1['return_L2']
- e['return_L3'] = p1['return_L3']
- e['usage_gas'] = p1['gas_total']
- e['date_gas'] = p1['gas_date']
- http = httplib2.Http()
- header = {"Content-Type":"application/json","User-Agent":"Python3 Energy monitor"}
- response, send = http.request("https://url.of.my.own/postp1.php","POST",headers=header, body=json.dumps(e))
- str_content = send.decode('utf-8')
- if str_content != "OK":
- log.info(str_content)
- lastLogAt = readAt
- usageArray = []
- returnArray = []
- datagram = b''
- lines_read = 0
- startFound = False
- endFound = False
- log.debug('Start reading lines')
- while not startFound or not endFound:
- try:
- line = self.serial.readline()
- log.debug('>> %s', line.decode('ascii').rstrip())
- except Exception as e:
- log.error(e)
- log.error('Read a total of %d lines', lines_read)
- break
- lines_read += 1
- if re.match(b'.*(?=/)', line):
- startFound = True
- endFound = False
- datagram = line.lstrip()
- elif re.match(b'(?=!)', line):
- endFound = True
- datagram = datagram + line
- else:
- datagram = datagram + line
- # TODO: build in some protection for infinite loops
- self._datagram = datagram
- log.debug('Done reading one packet (containing %d lines)' % len(datagram.splitlines()))
- log.debug('Total lines read from serial port: %d', lines_read)
- log.debug('Constructing P1Packet from raw data')
- p1 = {}
- p1['timestamp'] = '{:%Y%m%d%H%M%S}'.format(datetime.datetime.now())
- p1['header'] = self.get(b'^\s*(/.*)\r\n')
- p1['kwh_id'] = self.get(b'^0-0:96\.1\.1\(([^)]+)\)\r\n')
- p1['kwh_tariff'] = self.get_int(b'^0-0:96\.14\.0\(([0-9]+)\)\r\n')
- p1['kwh_low_usage'] = self.get_float(b'^1-0:1\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n')
- p1['kwh_low_return'] = self.get_float(b'^1-0:2\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n')
- p1['kwh_high_usage'] = self.get_float(b'^1-0:1\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n')
- p1['kwh_high_return'] = self.get_float(b'^1-0:2\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n')
- u = self.get_float(b'^1-0:1\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n')
- r = self.get_float(b'^1-0:2\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n')
- p1['kwh_usage'] = u
- p1['kwh_return'] = r
- p1['current_L1'] = self.get_int(b'^1-0:31\.7\.0\(([0-9]+)\*A\)\r\n')
- p1['current_L2'] = self.get_int(b'^1-0:51\.7\.0\(([0-9]+)\*A\)\r\n')
- p1['current_L3'] = self.get_int(b'^1-0:71\.7\.0\(([0-9]+)\*A\)\r\n')
- p1['usage_L1'] = self.get_float(b'^1-0:21\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n')
- p1['usage_L2'] = self.get_float(b'^1-0:41\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n')
- p1['usage_L3'] = self.get_float(b'^1-0:61\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n')
- p1['return_L1'] = self.get_float(b'^1-0:22\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n')
- p1['return_L2'] = self.get_float(b'^1-0:42\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n')
- p1['return_L3'] = self.get_float(b'^1-0:62\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n')
- p1['gas_id'] = self.get(b'^0-1:96\.1\.0\(([^)]+)\)\r\n')
- p1['gas_device'] = self.get_int(b'^0-1:24\.1\.0\((\d)+\)\r\n')
- p1['gas_total'] = self.get_float(b'^(?:0-1:24\.2\.1(?:\(\d+[SW]\))?)?\(([0-9]{5}\.[0-9]{3})(?:\*m3)?\)\r\n', 0)
- p1['gas_date'] = '20' + repr(self.get_int(b'^(?:0-1:24\.2\.1(?:\((\d+)[SW]\))?)?\([0-9]{5}\.[0-9]{3}(?:\*m3)?\)\r\n'))
- p1['msg_code'] = self.get(b'^0-0:96\.13\.1\((\d+)\)\r\n')
- p1['msg_text'] = self.get(b'^0-0:96\.13\.0\((.+)\)\r\n')
- # 0-1:24.2.1(170325200000W)(00494.157*m3)
- usageArray.append(u)
- returnArray.append(r)
- with open('/var/ramdisk1M/p1.json'.format(datetime.datetime.now()), 'w+') as outfile:
- json.dump(p1, outfile)
- # outfile.write('\n')
- except Exception as err:
- log.error(err)
- #log.error('Sleep for 60 seconds');
- #time.sleep(60)
- break
- def get_float(self, regex, default=None):
- result = self.get(regex, None)
- if not result:
- return default
- return float(self.get(regex, default))
- def get_int(self, regex, default=None):
- result = self.get(regex, None)
- if not result:
- return default
- return int(result)
- def get(self, regex, default=None):
- results = re.search(regex, self._datagram, re.MULTILINE)
- if not results:
- return default
- return results.group(1).decode('ascii')
- if __name__ == "__main__":
- daemon = MyDaemon('/home/p1meter/p1meter/p1meter.pid', '/dev/null', '/home/p1meter/p1meter/p1meter.out', '/home/p1meter/p1meter/p1meter.err')
- if len(sys.argv) == 2:
- if 'start' == sys.argv[1]:
- daemon.start()
- elif 'stop' == sys.argv[1]:
- daemon.stop()
- elif 'restart' == sys.argv[1]:
- daemon.restart()
- else:
- print ("Unknown command")
- sys.exit(2)
- sys.exit(0)
- else:
- print ("usage: %s start|stop|restart" % sys.argv[0])
- sys.exit(2)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement