Code

Added first version of ACPI support to the battery plugin
[collectd.git] / src / battery.c
1 /**
2  * collectd - src/battery.c
3  * Copyright (C) 2006  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Florian octo Forster <octo at verplant.org>
21  **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
27 #define MODULE_NAME "battery"
28 #define BUFSIZE 512
30 #if defined(KERNEL_LINUX)
31 # define BATTERY_HAVE_READ 1
32 #else
33 # define BATTERY_HAVE_READ 0
34 #endif
36 #define INVALID_VALUE 47841.29
38 static char *battery_current_file = "battery-%s/current.rrd";
39 static char *battery_voltage_file = "battery-%s/voltage.rrd";
40 static char *battery_charge_file  = "battery-%s/charge.rrd";
42 static char *ds_def_current[] =
43 {
44         "DS:current:GAUGE:25:U:U",
45         NULL
46 };
47 static int ds_num_current = 1;
49 static char *ds_def_voltage[] =
50 {
51         "DS:voltage:GAUGE:25:U:U",
52         NULL
53 };
54 static int ds_num_voltage = 1;
56 static char *ds_def_charge[] =
57 {
58         "DS:charge:GAUGE:25:0:U",
59         NULL
60 };
61 static int ds_num_charge = 1;
63 static int   battery_pmu_num = 0;
64 static char *battery_pmu_file = "/proc/pmu/battery_%i";
66 static void battery_init (void)
67 {
68 #if BATTERY_HAVE_READ
69         int len;
70         char filename[BUFSIZE];
72         for (battery_pmu_num = 0; ; battery_pmu_num++)
73         {
74                 len = snprintf (filename, BUFSIZE, battery_pmu_file, battery_pmu_num);
76                 if ((len >= BUFSIZE) || (len < 0))
77                         break;
79                 if (access (filename, R_OK))
80                         break;
81         }
82 #endif
84         return;
85 }
87 static void battery_current_write (char *host, char *inst, char *val)
88 {
89         char filename[BUFSIZE];
90         int len;
92         len = snprintf (filename, BUFSIZE, battery_current_file, inst);
93         if ((len >= BUFSIZE) || (len < 0))
94                 return;
96         rrd_update_file (host, filename, val,
97                         ds_def_current, ds_num_current);
98 }
100 static void battery_voltage_write (char *host, char *inst, char *val)
102         char filename[BUFSIZE];
103         int len;
105         len = snprintf (filename, BUFSIZE, battery_voltage_file, inst);
106         if ((len >= BUFSIZE) || (len < 0))
107                 return;
109         rrd_update_file (host, filename, val,
110                         ds_def_voltage, ds_num_voltage);
113 static void battery_charge_write (char *host, char *inst, char *val)
115         char filename[BUFSIZE];
116         int len;
118         len = snprintf (filename, BUFSIZE, battery_charge_file, inst);
119         if ((len >= BUFSIZE) || (len < 0))
120                 return;
122         rrd_update_file (host, filename, val,
123                         ds_def_charge, ds_num_charge);
126 #if BATTERY_HAVE_READ
127 static void battery_submit (char *inst, double current, double voltage, double charge)
129         int len;
130         char buffer[BUFSIZE];
132         if (current != INVALID_VALUE)
133         {
134                 len = snprintf (buffer, BUFSIZE, "N:%.3f", current);
136                 if ((len > 0) && (len < BUFSIZE))
137                         plugin_submit ("battery_current", inst, buffer);
138         }
139         else
140         {
141                 plugin_submit ("battery_current", inst, "N:U");
142         }
144         if (voltage != INVALID_VALUE)
145         {
146                 len = snprintf (buffer, BUFSIZE, "N:%.3f", voltage);
148                 if ((len > 0) && (len < BUFSIZE))
149                         plugin_submit ("battery_voltage", inst, buffer);
150         }
151         else
152         {
153                 plugin_submit ("battery_voltage", inst, "N:U");
154         }
156         if (charge != INVALID_VALUE)
157         {
158                 len = snprintf (buffer, BUFSIZE, "N:%.3f", charge);
160                 if ((len > 0) && (len < BUFSIZE))
161                         plugin_submit ("battery_charge", inst, buffer);
162         }
163         else
164         {
165                 plugin_submit ("battery_charge", inst, "N:U");
166         }
169 static void battery_read (void)
171 #ifdef KERNEL_LINUX
172         FILE *fh;
173         char buffer[BUFSIZE];
174         char filename[BUFSIZE];
175         
176         char *fields[8];
177         int numfields;
179         int i;
180         int len;
182         for (i = 0; i < battery_pmu_num; i++)
183         {
184                 char    batnum_str[BUFSIZE];
185                 double  current = INVALID_VALUE;
186                 double  voltage = INVALID_VALUE;
187                 double  charge  = INVALID_VALUE;
188                 double *valptr = NULL;
190                 len = snprintf (filename, BUFSIZE, battery_pmu_file, i);
191                 if ((len >= BUFSIZE) || (len < 0))
192                         continue;
194                 len = snprintf (batnum_str, BUFSIZE, "%i", i);
195                 if ((len >= BUFSIZE) || (len < 0))
196                         continue;
198                 if ((fh = fopen (filename, "r")) == NULL)
199                         continue;
201                 while (fgets (buffer, BUFSIZE, fh) != NULL)
202                 {
203                         numfields = strsplit (buffer, fields, 8);
205                         if (numfields < 3)
206                                 continue;
208                         if (strcmp ("current", fields[0]) == 0)
209                                 valptr = &current;
210                         else if (strcmp ("voltage", fields[0]) == 0)
211                                 valptr = &voltage;
212                         else if (strcmp ("charge", fields[0]) == 0)
213                                 valptr = &charge;
214                         else
215                                 valptr = NULL;
217                         if (valptr != NULL)
218                         {
219                                 char *endptr;
221                                 endptr = NULL;
222                                 errno  = 0;
224                                 *valptr = strtod (fields[2], &endptr) / 1000.0;
226                                 if ((fields[2] == endptr) || (errno != 0))
227                                         *valptr = INVALID_VALUE;
228                         }
229                 }
231                 if ((current != INVALID_VALUE)
232                                 || (voltage != INVALID_VALUE)
233                                 || (charge  != INVALID_VALUE))
234                         battery_submit (batnum_str, current, voltage, charge);
236                 fclose (fh);
237                 fh = NULL;
238         }
240         if (access ("/proc/acpi/battery", R_OK | X_OK) == 0)
241         {
242                 double  current = INVALID_VALUE;
243                 double  voltage = INVALID_VALUE;
244                 double  charge  = INVALID_VALUE;
245                 double *valptr = NULL;
246                 int charging = 0;
248                 struct dirent *ent;
249                 DIR *dh;
251                 if ((dh = opendir ("/proc/acpi/battery")) == NULL)
252                 {
253                         syslog (LOG_ERR, "Cannot open `/proc/acpi/battery': %s", strerror (errno));
254                         return;
255                 }
257                 while ((ent = readdir (dh)) != NULL)
258                 {
259                         len = snprintf (filename, BUFSIZE, "/proc/acpi/battery/%s/state", ent->d_name);
260                         if ((len >= BUFSIZE) || (len < 0))
261                                 continue;
263                         if ((fh = fopen (filename, "r")) == NULL)
264                         {
265                                 syslog (LOG_ERR, "Cannot open `%s': %s", filename, strerror (errno));
266                                 continue;
267                         }
269                         /*
270                          * [11:00] <@tokkee> $ cat /proc/acpi/battery/BAT1/state
271                          * [11:00] <@tokkee> present:                 yes
272                          * [11:00] <@tokkee> capacity state:          ok
273                          * [11:00] <@tokkee> charging state:          charging
274                          * [11:00] <@tokkee> present rate:            1724 mA
275                          * [11:00] <@tokkee> remaining capacity:      4136 mAh
276                          * [11:00] <@tokkee> present voltage:         12428 mV
277                          */
278                         while (fgets (buffer, BUFSIZE, fh) == NULL)
279                         {
280                                 numfields = strsplit (buffer, fields, 8);
282                                 if (numfields < 3)
283                                         continue;
285                                 if ((strcmp (fields[0], "present"))
286                                                 && (strcmp (fields[1], "rate:")))
287                                         valptr = &current;
288                                 else if ((strcmp (fields[0], "remaining"))
289                                                 && (strcmp (fields[1], "capacity:")))
290                                         valptr = &charge;
291                                 else if ((strcmp (fields[0], "present"))
292                                                 && (strcmp (fields[1], "voltage:")))
293                                         valptr = &voltage;
294                                 else
295                                         valptr = NULL;
297                                 if ((strcmp (fields[0], "charging"))
298                                                 && (strcmp (fields[1], "state:")))
299                                 {
300                                         if (strcmp (fields[2], "charging"))
301                                                 charging = 1;
302                                         else
303                                                 charging = 0;
304                                 }
306                                 if (valptr != NULL)
307                                 {
308                                         char *endptr;
310                                         endptr = NULL;
311                                         errno  = 0;
313                                         *valptr = strtod (fields[2], &endptr) / 1000.0;
315                                         if ((fields[2] == endptr) || (errno != 0))
316                                                 *valptr = INVALID_VALUE;
317                                 }
318                         }
320                         if ((current != INVALID_VALUE) && (charging == 0))
321                                         current *= -1;
323                         if ((current != INVALID_VALUE)
324                                         || (voltage != INVALID_VALUE)
325                                         || (charge  != INVALID_VALUE))
326                                 battery_submit (ent->d_name, current, voltage, charge);
328                         fclose (fh);
329                 }
331                 closedir (dh);
332         }
333 #endif /* KERNEL_LINUX */
335 #else
336 # define battery_read NULL
337 #endif /* BATTERY_HAVE_READ */
339 void module_register (void)
341         plugin_register (MODULE_NAME, battery_init, battery_read, NULL);
342         plugin_register ("battery_current", NULL, NULL, battery_current_write);
343         plugin_register ("battery_voltage", NULL, NULL, battery_voltage_write);
344         plugin_register ("battery_charge",  NULL, NULL, battery_charge_write);
347 #undef BUFSIZE
348 #undef MODULE_NAME