--- /dev/null
+TOPDIR=/root/turris
+
+include $(TOPDIR)/rules.mk
+include $(TOPDIR)/include/package.mk
+
+PC := PATH=$(STAGING_DIR_HOST)/bin:$(PATH) PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) PKG_CONFIG_LIBDIR=$(PKG_CONFIG_PATH) STAGING_PREFIX=$(STAGING_DIR)/usr $(PKG_CONFIG)
+MB_CFLAGS := $(shell $(PC) --cflags libmodbus)
+MB_LDFLAGS := $(shell $(PC) --libs libmodbus)
+
+export PATH=$(TARGET_PATH_PKG)
+CC=$(TARGET_CC_NOCACHE)
+LD=$(TARGET_LD_NOCACHE)
+CFLAGS=$(TARGET_CFLAGS) $(MB_CFLAGS) -std=gnu99
+LDFLAGS=$(TARGET_LDFLAGS) $(MB_LDFLAGS)
+
+all: power-cgi upload
+
+power-cgi: power-cgi.c
+
+upload:
+ rsync -av power-cgi micac:/www/burrow/power.cgi
--- /dev/null
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <modbus.h>
+
+typedef unsigned int uint;
+
+void die(const char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ vsyslog(LOG_ERR, msg, args);
+ // vfprintf(stderr, msg, args);
+ // fputc('\n', stderr);
+ printf("Status: 500\n");
+ printf("Content-Type: text/plain\n\n");
+ printf("Internal error, see syslog.\n");
+ exit(0);
+}
+
+static uint16_t reg[22];
+
+int32_t get_s32(uint i)
+{
+ if (reg[i+1] < 0x8000)
+ return (reg[i+1] << 16) | reg[i];
+ else
+ return ((reg[i+1] - 65536) * 65536) + reg[i];
+}
+
+int main(void)
+{
+ openlog("power.cgi", LOG_PID, LOG_LOCAL0);
+
+ modbus_t *ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);
+ if (!ctx)
+ die("Unable to establish Modbus context");
+ modbus_set_slave(ctx, 42);
+ if (modbus_connect(ctx) < 0)
+ die("Unable to connect to Modbus");
+
+ if (modbus_read_registers(ctx, 0, 22, reg) < 0)
+ die("Modbus read failed");
+
+ printf("Content-type: text/plain; version=0.0.4\n\n");
+
+ printf("# HELP pm_voltage Voltage between phases and neutral [V]\n");
+ printf("# TYPE pm_voltage gauge\n");
+ printf("pm_voltage{phase=\"L1N\"} %.1f\n", get_s32(0) / 10.);
+ printf("pm_voltage{phase=\"L2N\"} %.1f\n", get_s32(2) / 10.);
+ printf("pm_voltage{phase=\"L3N\"} %.1f\n", get_s32(4) / 10.);
+
+ printf("# HELP pm_current Current through phases [A]\n");
+ printf("# TYPE pm_current gauge\n");
+ printf("pm_current{phase=\"L1\"} %.3f\n", get_s32(6) / 1000.);
+ printf("pm_current{phase=\"L2\"} %.3f\n", get_s32(8) / 1000.);
+ printf("pm_current{phase=\"L3\"} %.3f\n", get_s32(10) / 1000.);
+
+ printf("# HELP pm_power Total power [W]\n");
+ printf("# TYPE pm_power gauge\n");
+ printf("pm_power %.1f\n", get_s32(12) / 10.);
+
+ printf("# HELP pm_energy Total energy [kWh]\n");
+ printf("# TYPE pm_energy gauge\n");
+ printf("pm_energy %.1f\n", get_s32(14) / 10.);
+
+ printf("# HELP pm_reactive_power Reactive power [VAr]\n");
+ printf("# TYPE pm_reactive_power gauge\n");
+ printf("pm_reactive_power %.1f\n", get_s32(18) / 10.);
+
+ printf("# HELP pm_reactive_energy Total reactive energy [kVArh]\n");
+ printf("# TYPE pm_reactive_energy gauge\n");
+ printf("pm_reactive_energy %.1f\n", get_s32(20) / 10.);
+
+ return 0;
+}