Closed Froschie closed 2 years ago
I've created the following utilities to deal with OBIS codes:
import re
from typing import List
OBIS_CODE_REGEX = r'^\d+-\d+:\d+.\d+.\d+\*\d+$' # Format: A-B:C.D.E*F
OBIS_HEX_REGEX = r'^[\da-fA-F]{12}$' # Format: twelve hex digits
def is_obis_code(str: str) -> bool:
return bool(re.match(OBIS_CODE_REGEX, str))
def is_obis_hex(str: str) -> bool:
return bool(re.match(OBIS_HEX_REGEX, str))
def obis_code_to_hex(obis: str) -> str:
if not is_obis_code(obis):
raise ValueError('Input does not represent a valid OBIS code')
groups: List[str] = re.split(r'\D+', obis)
return ''.join(['{:02x}'.format(int(group)) for group in groups])
def _obis_hex_to_groups(hex: str) -> List[int]:
if not is_obis_hex(hex):
raise ValueError('Input does not represent a valid OBIS hex')
return [int(hex[i:i + 2], 16) for i in range(0, len(hex), 2)]
def obis_hex_to_code(hex: str, short: bool = False) -> str:
groups = _obis_hex_to_groups(hex)
if short:
return '{0}.{1}.{2}'.format(*groups[2:-1])
return '{0}-{1}:{2}.{3}.{4}*{5}'.format(*groups)
Feel free to include them in this library. This project has helped me a lot 🙂
class ObisUtilsTestCase(TestCase):
def test_is_obis_code(self):
"""
Should be able to identify valid OBIS codes.
Format: A-B:C.D.E*F
"""
self.assertTrue(is_obis_code('1-0:1.8.0*255'))
# May not have empty groups
self.assertFalse(is_obis_code(':..*'))
# May not skip a group (F)
self.assertFalse(is_obis_code('1-0:1.8.0'))
# May not contain non-digit in a group (F)
self.assertFalse(is_obis_code('1-0:1.8.0*25A'))
def test_is_obis_hex(self):
"""
Should be able to identify valid OBIS hex codes.
Format: twelve hex digits
"""
self.assertTrue(is_obis_hex('0100010800ff'))
# May mix upper/lowercase hex digits (F)
self.assertTrue(is_obis_hex('0100010800fF'))
# May not contain non-hex digits (g)
self.assertFalse(is_obis_hex('0100010800g'))
# May not have less than 12 characters (11)
self.assertFalse(is_obis_hex('0100010800f'))
# May not have more than 12 characters (13)
self.assertFalse(is_obis_hex('0100010800fff'))
def test_obis_code_to_hex(self):
"""
Should be able to convert an OBIS code to an OBIS hex code.
"""
self.assertEqual(obis_code_to_hex('1-0:1.8.0*255'), '0100010800ff')
# Fails if the input is not a valid OBIS code
with self.assertRaises(ValueError):
obis_code_to_hex('1-0:1.8.0*25A')
def test_obis_hex_to_code(self):
"""
Should be able to convert an OBIS hex code to an OBIS code.
"""
self.assertEqual(obis_hex_to_code('0100010800ff'), '1-0:1.8.0*255')
self.assertEqual(obis_hex_to_code('0100010800ff', short=True), '1.8.0')
# Fails if the input is not a valid OBIS hex
with self.assertRaises(ValueError):
obis_hex_to_code('0100010800g')
with self.assertRaises(ValueError):
obis_hex_to_code('0100010800g', short=True)
Hello,
Great SML module for python. I´ll be using it soon for one of my scripts.
One improvement I´ve added in my script is to decoded the OBIX Hex strings you output.
https://www.promotic.eu/en/pmdoc/Subsystems/Comm/PmDrivers/IEC62056_OBIS.htm If looking at the whole HEX string is contains: A-B:C.D.E*F
Personally I think C.D.E is sufficient.
In my testing today simply decoded it with: obis_C = int(value[4:6], 16) obis_D = int(value[6:8], 16) obis_E = int(value[8:10], 16) obis_string = "{}.{}.{}".format(obis_C, obis_D, obis_E)
Would be great if your library would decode it directly instead of giving the RAW Hex value.
Thanks.