diff --git a/SunGather/exports/mqtt.py b/SunGather/exports/mqtt.py index 07a879e..1933832 100644 --- a/SunGather/exports/mqtt.py +++ b/SunGather/exports/mqtt.py @@ -25,7 +25,7 @@ class export_mqtt(object): self.mqtt_client.tls_set() try: - self.mqtt_client.connect(config.get('host'), port=config.get('port', 1883)) + self.mqtt_client.connect(config.get('host'), port=config.get('port', 1883), keepalive=60) self._isConfigured = True except Exception as err: logging.error(f"MQTT: Connection {config.get('host')}:{config.get('port', 1883)}") @@ -52,9 +52,6 @@ class export_mqtt(object): logging.info("MQTT: Skipped, Initial Configuration Failed") return False - # After a while you'll need to reconnect, so just reconnect before each publish - self.mqtt_client.reconnect() - if not self.model: self.model = inverter.get('device_type_code', 'unknown') self.model_clean = self.model.replace('.','').replace('-','') @@ -63,8 +60,18 @@ class export_mqtt(object): logging.debug(f'MQTT: Sensor Topic = {self.sensor_topic}') logging.debug(f"MQTT: Publishing: {self.sensor_topic} : {json.dumps(inverter)}") - result = self.mqtt_client.publish(self.sensor_topic, json.dumps(inverter).replace('"', '\"')) - result.wait_for_publish() + try: + result = self.mqtt_client.publish(self.sensor_topic, json.dumps(inverter).replace('"', '\"')) + result.wait_for_publish() + if result.rc == mqtt.MQTT_ERR_SUCCESS: + logging.info("MQTT: Published") + else: + logging.error(f"MQTT: Failed to publish with error code: {result.rc}") + if result.rc == mqtt.MQTT_ERR_NO_CONN: + logging.warning(f"MQTT: Attempting to reconnect to MQTT") + self.mqtt_client.reconnect() + except Exception as err: + logging.error(f"MQTT: Failed to publish with error: {err}") if self.homeassistant: if self.ha_discovery: @@ -89,15 +96,17 @@ class export_mqtt(object): config_msg['ic'] = "mdi:solar-power" config_msg['device'] = { "name":"Solar Inverter", "mf":"Sungrow", "mdl":self.model, "connections":[["address", self.inverter_ip ]]} - result = self.mqtt_client.publish(ha_topic, json.dumps(config_msg), retain=True) - result.wait_for_publish() - logging.info("MQTT: Published Home Assistant Discovery messages") + try: + result = self.mqtt_client.publish(ha_topic, json.dumps(config_msg), retain=True) + result.wait_for_publish() + if result.rc != mqtt.MQTT_ERR_SUCCESS: + logging.error(f"MQTT: Failed to publish with error code: {result.rc}") + if result.rc == mqtt.MQTT_ERR_NO_CONN: + logging.warning(f"MQTT: Attempting to reconnect to MQTT") + self.mqtt_client.reconnect() + except Exception as err: + logging.error(f"MQTT: Failed to publish with error: {err}") self.ha_discovery = False + logging.info("MQTT: Published Home Assistant Discovery messages") - if result.rc != mqtt.MQTT_ERR_SUCCESS: - # See https://github.com/eclipse/paho.mqtt.python/blob/master/src/paho/mqtt/client.py#L149 for error code mapping - logging.error(f"MQTT: Failed to publish with error code: {result.rc}") - else: - logging.info("MQTT: Published") - - return result \ No newline at end of file + return True \ No newline at end of file diff --git a/SunGather/exports/pvoutput.py b/SunGather/exports/pvoutput.py index e108fb4..d8b0093 100644 --- a/SunGather/exports/pvoutput.py +++ b/SunGather/exports/pvoutput.py @@ -27,11 +27,9 @@ class export_pvoutput(object): self.rate_limit = config.get('rate_limit', 60) self.status_interval = config.get('status_interval',5) self.batch_points = config.get('batch_points',1) - self.inverter_data = { "v1": 0, "v2": 0, "v3": 0, "v4": 0, "v5": 0, "v6": 0, "v7": 0, "v8": 0, "v9": 0, "v10": 0, "v11": 0, "v12": 0 } - self.inverter_data_count = 0 + self.collected_data = {} self.payload_data = None self.batch_count = 0 - self.payload_format = "{date},{time},{v1},{v2},{v3},{v4},{v5},{v6},{v7},{v8},{v9},{v10},{v11},{v12}" for parameter in config.get('parameters'): self.parameters.append(parameter) @@ -78,46 +76,71 @@ class export_pvoutput(object): # Add new data to old data and increase count of data points for parameter in self.parameters: if parameter.get('name')[0] == 'v': - if inverter.get(parameter.get('register')): - if parameter.get('multiple'): - self.inverter_data[parameter.get('name')] = round(self.inverter_data[parameter.get('name')] + (inverter.get(parameter.get('register')) * parameter.get('multiple')),3) + if not self.collected_data.get(parameter.get('name'),False): + if inverter.get(parameter.get('register')): + self.collected_data[parameter.get('name')] = 0 else: - self.inverter_data[parameter.get('name')] = round(self.inverter_data[parameter.get('name')] + inverter.get(parameter.get('register')),3) + logging.warning(f"PVOutput: {parameter.get('name')} configured to use {parameter.get('register')} but inverter is not returning this register") + + if parameter.get('multiple'): + self.collected_data[parameter.get('name')] = round(self.collected_data[parameter.get('name')] + (inverter.get(parameter.get('register')) * parameter.get('multiple')),3) else: - logging.warning(f"PVOutput: {parameter.get('name')} configured to use {parameter.get('register')} but inverter is not returning this register") - elif parameter.get('name') == 'c1': - c1 = parameter.get('value') - self.inverter_data_count +=1 + self.collected_data[parameter.get('name')] = round(self.collected_data[parameter.get('name')] + inverter.get(parameter.get('register')),3) + if parameter.get('name') == 'c1': + cumulative_energy = parameter.get('value') + + if self.collected_data.get('count',False): + self.collected_data['count'] +=1 + else: + self.collected_data['count'] = 1 + logging.info('PVOutput: Data logged') - logging.debug(f'PVOutput: Points: {self.batch_count} Data: {self.inverter_data}, c1={str(c1)}') + logging.debug(f'PVOutput: Data: {self.collected_data}') # Process data points every status_interval if int(now.strftime("%M")) % self.status_interval == 0 and not now.strftime("%H:%M") == self.latest_run.strftime("%H:%M"): - for v in self.inverter_data: - if not self.inverter_data[v] == 0: - self.inverter_data[v] = round(self.inverter_data[v] / self.inverter_data_count, 2) - self.inverter_data_count = 0 + for v in self.collected_data: + if v[0] == 'v' and not self.collected_data[v] == 0: + self.collected_data[v] = round(self.collected_data[v] / self.collected_data['count'], 2) - payload = self.payload_format - payload = payload.replace('{date}',now.strftime("%Y%m%d")) - payload = payload.replace('{time}',now.strftime("%H:%M")) + data_point = str(now.strftime("%Y%m%d")) + "," + str(now.strftime("%H:%M")) - for data in self.inverter_data: - payload = payload.replace('{' + data + '}',str(self.inverter_data.get(data))) + for x in range(1, 13): + v = 'v' + str(x) + if self.collected_data.get(v): + data_point = data_point + "," + str(self.collected_data[v]) + else: + data_point = data_point + "," - self.inverter_data = { "v1": 0, "v2": 0, "v3": 0, "v4": 0, "v5": 0, "v6": 0, "v7": 0, "v8": 0, "v9": 0, "v10": 0, "v11": 0, "v12": 0 } + if self.collected_data.get('v2', False) and self.collected_data.get('v4', False): + net_data = 1 + else: + net_data = 0 + + self.collected_data = {} + + print(data_point) if self.payload_data: self.payload_data = self.payload_data + ";" else: self.payload_data = "" - self.payload_data = self.payload_data + payload + self.payload_data = self.payload_data + data_point self.batch_count +=1 if self.batch_count == self.batch_points: - payload = {'data': self.payload_data, 'c1': str(c1)} + + payload = {} + payload['data'] = self.payload_data + + if net_data > 0: + payload['n'] = net_data + if 'cumulative_energy' in locals(): + payload['c1'] = cumulative_energy + logging.debug("PVOutput: Request; " + self.statusbatch_url + ", " + str(self.headers) + " : " + str(payload)) + response = requests.post(url=self.statusbatch_url, headers=self.headers, params=payload) self.batch_count = 0 diff --git a/SunGather/registers.yaml b/SunGather/registers.yaml index 157a1a5..0592dd5 100644 --- a/SunGather/registers.yaml +++ b/SunGather/registers.yaml @@ -254,7 +254,7 @@ registers: address: 5017 datatype: "S32" # Documentation says Unsigned, but seems to be returning Signed 32bit - name: "phase_a_voltage" - level: 1 + level: 1 address: 5019 datatype: "U16" multiple: 0.1 diff --git a/SunGather/sungather.py b/SunGather/sungather.py index 0a64ba3..f6273f6 100644 --- a/SunGather/sungather.py +++ b/SunGather/sungather.py @@ -136,7 +136,7 @@ def scrape_inverter(): pass scrape_end = datetime.now() - logging.info(f'Inventer: Successfully scrapped in {(scrape_end - scrape_start).seconds}.{(scrape_end - scrape_start).microseconds} secs') + logging.info(f'Inverter: Successfully scraped in {(scrape_end - scrape_start).seconds}.{(scrape_end - scrape_start).microseconds} secs') return True diff --git a/SunGather/version.py b/SunGather/version.py index db9cf74..aa62704 100644 --- a/SunGather/version.py +++ b/SunGather/version.py @@ -1 +1 @@ -__version__ = '0.2.3' \ No newline at end of file +__version__ = '0.2.4' \ No newline at end of file