From e45fc0d19afaaaca0f3ac6412a642caa587c8239 Mon Sep 17 00:00:00 2001 From: prein2 Date: Thu, 3 Oct 2019 22:22:32 +0200 Subject: [PATCH] Create mbus-serial-request-data-multi-reply_Aestron630 This will send the right dataframe needed for Aestron 630M Mbus meter --- ...serial-request-data-multi-reply_Aestron630 | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 tools/mbus-serial-request-data-multi-reply_Aestron630 diff --git a/tools/mbus-serial-request-data-multi-reply_Aestron630 b/tools/mbus-serial-request-data-multi-reply_Aestron630 new file mode 100644 index 0000000..1277853 --- /dev/null +++ b/tools/mbus-serial-request-data-multi-reply_Aestron630 @@ -0,0 +1,139 @@ +#!/usr/bin/python + +import argparse +import serial +import time +import simplejson as json +import yaml +import sys +import urllib2 + +try: + import meterbus +except ImportError: + import sys + sys.path.append('../') + import meterbus + + +def ping_address(ser, address, retries=5): + for i in range(0, retries + 1): + meterbus.send_ping_frame(ser, address) + try: + frame = meterbus.load(meterbus.recv_frame(ser, 1)) + if isinstance(frame, meterbus.TelegramACK): + return True + except meterbus.MBusFrameDecodeError: + pass + + return False + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Request data over serial M-Bus for devices.') + parser.add_argument('-d', action='store_true', + help='Enable verbose debug') + parser.add_argument('-b', '--baudrate', + type=int, default=2400, + help='Serial bus baudrate') + parser.add_argument('-a', '--address', + type=str, default=meterbus.ADDRESS_BROADCAST_REPLY, + help='Primary or secondary address') + parser.add_argument('-r', '--retries', + type=int, default=5, + help='Number of ping retries for each address') + parser.add_argument('-o', '--output', default="json", + help='Output format') + parser.add_argument('device', type=str, help='Serial device or URI') + args = parser.parse_args() + + meterbus.debug(args.d) + + address = args.address + try: + if 0 <= int(args.address) <= 254: + address = int(args.address) + except ValueError: + pass + + try: + ibt = meterbus.inter_byte_timeout(args.baudrate) + with serial.serial_for_url(args.device, + args.baudrate, 8, 'E', 1, + inter_byte_timeout=ibt, + timeout=1) as ser: + frame = None + + if meterbus.is_primary_address(address): + if False == ping_address(ser, address, 0): + sys.exit(1) + + meterbus.send_request_frame_multi(ser, address,"\x68\x03\x03\x68\x53\x01\xb1\x05\x16") + frame = meterbus.load( + meterbus.recv_frame(ser)) + + elif meterbus.is_secondary_address(address): + if False == ping_address(ser, meterbus.ADDRESS_NETWORK_LAYER, 0): + ping_address(ser, meterbus.ADDRESS_BROADCAST_NOREPLY, 0) + + meterbus.send_select_frame(ser, address) + frame = meterbus.load(meterbus.recv_frame(ser, 1)) + assert isinstance(frame, meterbus.TelegramACK) + + req = meterbus.send_request_frame_multi( + ser, meterbus.ADDRESS_NETWORK_LAYER) + + try: + frame = meterbus.load(meterbus.recv_frame(ser)) + except meterbus.MBusFrameDecodeError: + frame = None + + while frame and frame.more_records_follow: + # toogle FCB on and off + req.header.cField.parts[0] ^= meterbus.CONTROL_MASK_FCB + + req = meterbus.send_request_frame_multi( + ser, meterbus.ADDRESS_NETWORK_LAYER, req) + + next_frame = meterbus.load(meterbus.recv_frame(ser)) + frame += next_frame + + if frame is not None: + recs = [] + for rec in frame.records: + recs.append({ + 'value': rec.value, + 'unit': rec.unit + }) + + ydata = { + 'manufacturer': frame.body.bodyHeader.manufacturer_field.decodeManufacturer, + 'identification': ''.join(map('{:02x}'.format, frame.body.bodyHeader.id_nr)), + 'access_no': frame.body.bodyHeader.acc_nr_field.parts[0], + 'medium': frame.body.bodyHeader.measure_medium_field.parts[0], + 'records': recs + } + + if args.output == 'json': + print(json.dumps(ydata, indent=4, sort_keys=True)) + Power = ydata['records'][10]['value'] + URL = ("http://localhost:8080/json.htm?type=command¶m=udevice&idx=196&nvalue=0&svalue=%.1f" % Power) + print URL + result = json.load(urllib2.urlopen(URL)) + print result + + elif args.output == 'yaml': + def float_representer(dumper, value): + if int(value) == value: + text = '{0:.4f}'.format(value).rstrip('0').rstrip('.') + return dumper.represent_scalar(u'tag:yaml.org,2002:int', text) + else: + text = '{0:.4f}'.format(value).rstrip('0').rstrip('.') + return dumper.represent_scalar(u'tag:yaml.org,2002:float', text) + + yaml.add_representer(float, float_representer) + + print(yaml.dump(ydata, default_flow_style=False, allow_unicode=True, encoding=None)) + + except serial.serialutil.SerialException as e: + print(e)