import paho.mqtt.client as mqtt import logging import time from mqtttopic import * import victronclient import dbus logger = logging.getLogger('main') class publisher: def __init__(self): self.client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1) self.sensors = {} self.mqtt_discovery_next_time = 0 self.client.on_connect = self.on_connect while True: try: self.client.connect(broker,port, 60) self.client.loop_start() break except Exception as e: logger.info("Unable to connect to mqtt: {!r}".format(e)) time.sleep(5) def dbus_to_python(self,data): ''' convert dbus data types to python native data types ''' if isinstance(data, dbus.String): data = str(data) elif isinstance(data, dbus.Boolean): data = bool(data) elif isinstance(data, dbus.Int64): data = int(data) elif isinstance(data, dbus.Int32): data = int(data) elif isinstance(data, dbus.Double): data = float(data) elif isinstance(data, dbus.Array): data = [self.dbus_to_python(value) for value in data] elif isinstance(data, dbus.Dictionary): new_data = dict() for key in data.keys(): new_data[self.dbus_to_python(key)] = self.dbus_to_python(data[key]) data = new_data return data def check_update_value(self, name, value): value = self.dbus_to_python(value) if not name in self.sensors: self.sensors[name] = {'value': None, 'writable' : False} if not (type(value) is int or type(value) is str or type(value) is float or value is None): print ("Value {} for {} is not accepted (type {})".format(value, name,type(value))) return if not name in self.sensors or self.sensors[name]['value'] != value: self.client.publish(topic_base + name + topic_state_postfix, value,retain=True) self.sensors[name]['value'] = value def publish_controller(self, controller): self.check_update_value('chargemode', controller.get_chargemode_int()) self.check_update_value('chargevalue', controller.get_chargevalue()) self.check_update_value('actual_returndelivery', round(controller.get_battery_total_net_delivery()/ 1000,2)) self.check_update_value('actual_consumption', round(controller.get_battery_total_net_usage()/ 1000,2)) self.check_update_value('gridpower', controller.victronconn.get_power_usage()) self.check_update_value('soc', controller.victronconn.get_soc()) self.check_update_value('setpoint', controller.victronconn.get_setpoint()) self.check_update_value('battery_current', controller.victronconn.get_battery_current()) self.check_update_value('battery_power', controller.victronconn.get_battery_power()) self.check_update_value('battery_max_chargecurrent', controller.victronconn.get_battery_max_chargecurrent()) def publish_battery(self, battery: victronclient.battery): self.check_update_value(battery.name + '_soc', battery.get_soc()) self.check_update_value(battery.name + '_power', battery.get_power()) self.check_update_value(battery.name + '_current', battery.get_current()) self.check_update_value(battery.name + '_temperature', battery.get_temperature()) self.check_update_value(battery.name + '_sum', battery.get_voltage_sum()) self.check_update_value(battery.name + '_low', battery.get_voltage_lowest()) self.check_update_value(battery.name + '_high', battery.get_voltage_highest()) self.check_update_value(battery.name + '_diff', battery.get_voltage_diff()) def loop(self): pass #rc = self.client.loop(timeout=0.1) #if rc != 0: # if not self.client.is_connected: # logger.warning("MQTT publisher connection disconnected. Reconnecting...") # self.client.reconnect() #if self.mqtt_discovery_next_time < time.time(): # self.mqtt_discovery_next_time = time.time() + 60 # self.announce() # The callback for when the client receives a CONNACK response from the server. def on_connect(self,client, userdata, flags, rc): logger.info("Connected publisher to mqtt with result code "+str(rc))