7 typedef unsigned int uint;
9 void die(const char *msg, ...)
13 vsyslog(LOG_ERR, msg, args);
14 // vfprintf(stderr, msg, args);
15 // fputc('\n', stderr);
16 printf("Status: 500\n");
17 printf("Content-Type: text/plain\n\n");
18 printf("Internal error, see syslog.\n");
22 static uint16_t reg[22];
24 int32_t get_s32(uint i)
26 if (reg[i+1] < 0x8000)
27 return (reg[i+1] << 16) | reg[i];
29 return ((reg[i+1] - 65536) * 65536) + reg[i];
34 openlog("power.cgi", LOG_PID, LOG_LOCAL0);
36 modbus_t *ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);
38 die("Unable to establish Modbus context");
39 modbus_set_slave(ctx, 42);
40 if (modbus_connect(ctx) < 0)
41 die("Unable to connect to Modbus");
43 if (modbus_read_registers(ctx, 0, 22, reg) < 0)
44 die("Modbus read failed");
46 printf("Content-type: text/plain; version=0.0.4\n\n");
48 printf("# HELP pm_voltage Voltage between phases and neutral [V]\n");
49 printf("# TYPE pm_voltage gauge\n");
50 printf("pm_voltage{phase=\"L1N\"} %.1f\n", get_s32(0) / 10.);
51 printf("pm_voltage{phase=\"L2N\"} %.1f\n", get_s32(2) / 10.);
52 printf("pm_voltage{phase=\"L3N\"} %.1f\n", get_s32(4) / 10.);
54 printf("# HELP pm_current Current through phases [A]\n");
55 printf("# TYPE pm_current gauge\n");
56 printf("pm_current{phase=\"L1\"} %.3f\n", get_s32(6) / 1000.);
57 printf("pm_current{phase=\"L2\"} %.3f\n", get_s32(8) / 1000.);
58 printf("pm_current{phase=\"L3\"} %.3f\n", get_s32(10) / 1000.);
60 printf("# HELP pm_power Total power [W]\n");
61 printf("# TYPE pm_power gauge\n");
62 printf("pm_power %.1f\n", get_s32(12) / 10.);
64 printf("# HELP pm_energy Total energy [kWh]\n");
65 printf("# TYPE pm_energy gauge\n");
66 printf("pm_energy %.1f\n", get_s32(14) / 10.);
68 printf("# HELP pm_reactive_power Reactive power [VAr]\n");
69 printf("# TYPE pm_reactive_power gauge\n");
70 printf("pm_reactive_power %.1f\n", get_s32(18) / 10.);
72 printf("# HELP pm_reactive_energy Total reactive energy [kVArh]\n");
73 printf("# TYPE pm_reactive_energy gauge\n");
74 printf("pm_reactive_energy %.1f\n", get_s32(20) / 10.);