from threading import Event from loguru import logger from MqttBase import AbstractMqttPublisher import json import datetime def floatAdaptor(i): return float(f"{i:0.2f}") if i else 0.0 def onOffAdaptor(i): return i[0] != 0 REGISTERS = [ { "slave":2, "addr":0x0048, "type":"input", "attr": "importEnergy", "name":"Import active energy", "unit":"kWh", "adaptor": floatAdaptor }, { "slave":2, "addr":0x004a, "type":"input", "attr": "exportEnergy", "name":"Export active energy", "unit":"kWh", "adaptor": floatAdaptor }, { "slave":2, "addr":0x000c, "type":"input", "attr": "power", "name":"Power", "unit":"W", "adaptor": floatAdaptor }, { "slave":2, "addr":0x0000, "type":"input", "attr": "voltage", "name":"Voltage", "unit":"V", "adaptor": floatAdaptor }, { "slave":2, "addr":0x0006, "type":"input", "attr": "current", "name":"Current", "unit":"A", "adaptor": floatAdaptor }, { "slave":1, "addr":0x0001, "type":"holding", "attr": "state", "name":"State", "unit":"-", "adaptor": onOffAdaptor }, ] class MeterPublish(AbstractMqttPublisher): def __init__(self, config, modbusHandler): super().__init__(config) self.modbusHandler = modbusHandler self.registers = REGISTERS def localLoop(self): cnt = 0 while not self.killBill: cnt += 1 topic = self.config["meterPublishTopic"] payload = str(cnt) try: payload = { r['attr']: r['adaptor'](None) for r in self.registers } payload['status'] = "Error" payload['timestamp'] = datetime.datetime.isoformat(datetime.datetime.utcnow()) for reg in self.registers: v = self.modbusHandler.readRegister(reg['type'], reg['slave'], reg['addr']) logger.debug(f"{reg['name']}: {v} {reg['unit']}") payload[reg['attr']] = reg['adaptor'](v) payload['status'] = "Ok" except Exception as e: logger.error(f"Caught exception: {str(e)}") payload['cnt'] = cnt payloadStr = json.dumps(payload) self.client.publish(topic, payloadStr) logger.info(f"mqtt message sent: {topic} -> {payloadStr}") self.killEvent.wait(timeout=float(self.config["meterPublishPeriod"]))