import std/[asyncdispatch, asyncnet] import std/[os, posix] import std/[tables, json, options] import std/math import nmqtt import types, modbus var mqttContext* {.threadvar.} : MqttCtx proc round* [T: float32|float64](value: T, places: int = 0): float = if places == 0: result = round(value) else: result = value * pow(10.0, T(places)) result = floor(result) result = result / pow(10.0, T(places)) proc CtrlCHook* () {.noconv.} = echo "Ctrl+C fired! \nStopping Server now!" waitFor mqttContext.disconnect() quit() proc updatePowermeter (deviceAddress: uint8, deviceName: string) {.async.} = let json = %* { "id": deviceAddress, "deviceName": deviceName, "voltage": mbFloatDCBA(await readInputRegisters(deviceAddress, 0, 2)).round(3), "power": mbFloatDCBA(await readInputRegisters(deviceAddress, 12, 2)).round(3), "frequency": mbFloatDCBA(await readInputRegisters(deviceAddress, 70, 2)).round(3), "cosphi": mbFloatDCBA(await readInputRegisters(deviceAddress, 30, 2)).round(3), "import": mbFloatDCBA(await readInputRegisters(deviceAddress, 72, 2)).round(3) } if mqttContext.isConnected: await mqttContext.publish("sdm2mqtt/"&deviceName, $json, 2, true) for key, value in json: if key != "deviceName": await sleepAsync(250) await mqttContext.publish("sdm2mqtt/" & deviceName & "/" & key, $value, 2, true) proc updatePowermeters (config: Config) {.async.} = await sleepAsync(500) while true: for name, address in config.devices.pairs(): try: await updatePowermeter(address, name) except: echo "Error[updatePowermeters]:\n", getCurrentExceptionMsg() await sleepAsync(int(config.updateInterval * 1000)) proc main () {.async.} = setControlCHook(CtrlCHook) onSignal(SIGTERM): echo "Got SIGTERM! \nStopping Server now!" waitFor mqttContext.disconnect() quit() var configFile = "./config.json" if getEnv("CONFIG_PATH") != "": configFile = getEnv("CONFIG_PATH") if not fileExists(configFile): echo "Config file not found" quit() let config = parseFile(configFile).to(Config) await initModbus(config.modbus.host, config.modbus.port) mqttContext = newMqttCtx("sdm2mqtt") mqttContext.set_host(config.mqtt.host, config.mqtt.port) mqttContext.set_verbosity(1) if (config.mqtt.username.isSome and config.mqtt.password.isSome): mqttContext.set_auth(config.mqtt.username.get, config.mqtt.password.get) await mqttContext.start() asyncCheck updatePowermeters(config) runForever() waitFor main()