diff --git a/xcel_itron2mqtt/configs/endpoints_3_2_39.yaml b/xcel_itron2mqtt/configs/endpoints_3_2_39.yaml new file mode 100644 index 0000000..18c76d5 --- /dev/null +++ b/xcel_itron2mqtt/configs/endpoints_3_2_39.yaml @@ -0,0 +1,41 @@ +- Instantaneous Demand: + url: '/upt/1/mr/1/r' + tags: + value: + entity_type: sensor + device_class: power + unit_of_measurement: W +- Current Summation Received: + url: '/upt/1/mr/2/rs/1/r/1' + tags: + timePeriod: + - duration: + entity_type: sensor + device_class: timestamp + value_template: '{{ as_datetime( value ) }}' + - start: + entity_type: sensor + device_class: timestamp + value_template: '{{ as_datetime( value ) }}' + value: + entity_type: sensor + device_class: energy + unit_of_measurement: Wh + state_class: total +- Current Summation Delivered: + url: '/upt/1/mr/3/rs/1/r/1' + tags: + timePeriod: + - duration: + entity_type: sensor + device_class: timestamp + value_template: '{{ as_datetime( value ) }}' + - start: + entity_type: sensor + device_class: timestamp + value_template: '{{ as_datetime( value ) }}' + value: + entity_type: sensor + device_class: energy + unit_of_measurement: Wh + state_class: total diff --git a/xcel_itron2mqtt/endpoints.yaml b/xcel_itron2mqtt/configs/endpoints_default.yaml similarity index 100% rename from xcel_itron2mqtt/endpoints.yaml rename to xcel_itron2mqtt/configs/endpoints_default.yaml diff --git a/xcel_itron2mqtt/xcelEndpoint.py b/xcel_itron2mqtt/xcelEndpoint.py index 5d6a3a6..9584aee 100644 --- a/xcel_itron2mqtt/xcelEndpoint.py +++ b/xcel_itron2mqtt/xcelEndpoint.py @@ -68,12 +68,14 @@ def parse_response(response: str, tags: dict) -> dict: for val_items in v: for k2, v2 in val_items.items(): search_val = f'{IEEE_PREFIX}{k2}' - value = root.find(f'.//{search_val}').text - readings_dict[f'{k}{k2}'] = value + if root.find(f'.//{search_val}') is not None: + value = root.find(f'.//{search_val}').text + readings_dict[f'{k}{k2}'] = value else: search_val = f'{IEEE_PREFIX}{k}' - value = root.find(f'.//{IEEE_PREFIX}{k}').text - readings_dict[k] = value + if root.find(f'.//{IEEE_PREFIX}{k}') is not None: + value = root.find(f'.//{IEEE_PREFIX}{k}').text + readings_dict[k] = value return readings_dict @@ -178,4 +180,4 @@ def run(self) -> None: Returns: None """ reading = self.get_reading() - self.process_send_mqtt(reading) \ No newline at end of file + self.process_send_mqtt(reading) diff --git a/xcel_itron2mqtt/xcelMeter.py b/xcel_itron2mqtt/xcelMeter.py index db47492..d6cd15c 100644 --- a/xcel_itron2mqtt/xcelMeter.py +++ b/xcel_itron2mqtt/xcelMeter.py @@ -59,13 +59,10 @@ def __init__(self, name: str, ip_address: str, port: int, creds: Tuple[str, str] # Create a new requests session based on the passed in ip address and port # self.requests_session = self.setup_session(creds, ip_address) - - # List to store our endpoint objects in - self.endpoints_list = self.load_endpoints('endpoints.yaml') # Set to uninitialized self.initalized = False - + @retry(stop=stop_after_attempt(15), wait=wait_exponential(multiplier=1, min=1, max=15), before_sleep=before_sleep_log(logger, logging.WARNING), @@ -93,17 +90,22 @@ def setup(self) -> None: # Send homeassistant a new device config for the meter self.send_mqtt_config() + # The swVer will dictate which version of endpoints we use + endpoints_file_ver = 'default' if str(self._swVer) != '3.2.39' else '3_2_39' + # List to store our endpoint objects in + self.endpoints_list = self.load_endpoints(f'configs/endpoints_{endpoints_file_ver}.yaml') + # create endpoints from list self.endpoints = self.create_endpoints(self.endpoints_list, self.device_info) # ready to go self.initalized = True - + def get_hardware_details(self, hw_info_url: str, hw_names: list) -> dict: """ - Queries the meter hardware endpoint at the ip address passed - to the class. - + Queries the meter hardware endpoint at the ip address passed + to the class. + Returns: dict, {: } """ query_url = f'{self.url}{hw_info_url}' @@ -114,7 +116,7 @@ def get_hardware_details(self, hw_info_url: str, hw_names: list) -> dict: hw_info_dict = {} for name in hw_names: hw_info_dict[name] = root.find(f'.//{IEEE_PREFIX}{name}').text - + return hw_info_dict @staticmethod @@ -131,7 +133,7 @@ def setup_session(creds: tuple, ip_address: str) -> requests.Session: session.mount('https://{ip_address}', CCM8Adapter()) return session - + @staticmethod def load_endpoints(file_path: str) -> list: """ @@ -141,20 +143,20 @@ def load_endpoints(file_path: str) -> list: """ with open(file_path, mode='r', encoding='utf-8') as file: endpoints = yaml.safe_load(file) - + return endpoints - + def create_endpoints(self, endpoints: dict, device_info: dict) -> None: # Build query objects for each endpoint query_obj = [] for point in endpoints: for endpoint_name, v in point.items(): request_url = f'{self.url}{v["url"]}' - query_obj.append(xcelEndpoint(self.requests_session, self.mqtt_client, + query_obj.append(xcelEndpoint(self.requests_session, self.mqtt_client, request_url, endpoint_name, v['tags'], device_info)) - + return query_obj - + @staticmethod def get_mqtt_port() -> int: """ @@ -167,7 +169,7 @@ def get_mqtt_port() -> int: # If environment variable for MQTT port is set, use that # if not, use the default mqtt_port = int(env_port) if env_port else 1883 - + return mqtt_port @staticmethod @@ -241,4 +243,3 @@ def run(self) -> None: sleep(self.POLLING_RATE) for obj in self.endpoints: obj.run() - \ No newline at end of file