b87b24ee39b6209c41fc0da16521ce17c5280ce7
[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  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26
27 #define MODULE_NAME "battery"
28 #define BUFSIZE 512
29
30 #if defined(KERNEL_LINUX)
31 # define BATTERY_HAVE_READ 1
32 #else
33 # define BATTERY_HAVE_READ 0
34 #endif
35
36 static char *battery_current_file = "battery-%s/current.rrd";
37 static char *battery_voltage_file = "battery-%s/voltage.rrd";
38 static char *battery_charge_file  = "battery-%s/charge.rrd";
39
40 static char *ds_def_current[] =
41 {
42         "DS:current:GAUGE:25:0:U",
43         NULL
44 };
45 static int ds_num_current = 1;
46
47 static char *ds_def_voltage[] =
48 {
49         "DS:voltage:GAUGE:25:0:U",
50         NULL
51 };
52 static int ds_num_voltage = 1;
53
54 static char *ds_def_charge[] =
55 {
56         "DS:charge:GAUGE:25:0:U",
57         NULL
58 };
59 static int ds_num_charge = 1;
60
61 static int   battery_pmu_num = 0;
62 static char *battery_pmu_file = "/proc/pmu/battery_%i";
63
64 static void battery_init (void)
65 {
66 #if BATTERY_HAVE_READ
67         int len;
68         char filename[BUFSIZE];
69
70         for (battery_pmu_num = 0; ; battery_pmu_num++)
71         {
72                 len = snprintf (filename, BUFSIZE, battery_pmu_file, battery_pmu_num);
73
74                 if ((len >= BUFSIZE) || (len < 0))
75                         break;
76
77                 if (access (filename, R_OK))
78                         break;
79         }
80 #endif
81
82         return;
83 }
84
85 static void battery_current_write (char *host, char *inst, char *val)
86 {
87         char filename[BUFSIZE];
88         int len;
89
90         len = snprintf (filename, BUFSIZE, battery_current_file, inst);
91         if ((len >= BUFSIZE) || (len < 0))
92                 return;
93
94         rrd_update_file (host, filename, val,
95                         ds_def_current, ds_num_current);
96 }
97
98 static void battery_voltage_write (char *host, char *inst, char *val)
99 {
100         char filename[BUFSIZE];
101         int len;
102
103         len = snprintf (filename, BUFSIZE, battery_voltage_file, inst);
104         if ((len >= BUFSIZE) || (len < 0))
105                 return;
106
107         rrd_update_file (host, filename, val,
108                         ds_def_voltage, ds_num_voltage);
109 }
110
111 static void battery_charge_write (char *host, char *inst, char *val)
112 {
113         char filename[BUFSIZE];
114         int len;
115
116         len = snprintf (filename, BUFSIZE, battery_charge_file, inst);
117         if ((len >= BUFSIZE) || (len < 0))
118                 return;
119
120         rrd_update_file (host, filename, val,
121                         ds_def_charge, ds_num_charge);
122 }
123
124 #if BATTERY_HAVE_READ
125 static void battery_submit (int batnum, double current, double voltage, double charge)
126 {
127         int len;
128         char buffer[BUFSIZE];
129         char batnum_str[BUFSIZE];
130
131         len = snprintf (batnum_str, BUFSIZE, "%i", batnum);
132         if ((len >= BUFSIZE) || (len < 0))
133                 return;
134
135         if (current > 0.0)
136         {
137                 len = snprintf (buffer, BUFSIZE, "N:%.3f", current);
138
139                 if ((len > 0) && (len < BUFSIZE))
140                         plugin_submit ("battery_current", batnum_str, buffer);
141         }
142
143         if (voltage > 0.0)
144         {
145                 len = snprintf (buffer, BUFSIZE, "N:%.3f", voltage);
146
147                 if ((len > 0) && (len < BUFSIZE))
148                         plugin_submit ("battery_voltage", batnum_str, buffer);
149         }
150
151         if (charge > 0.0)
152         {
153                 len = snprintf (buffer, BUFSIZE, "N:%.3f", charge);
154
155                 if ((len > 0) && (len < BUFSIZE))
156                         plugin_submit ("battery_charge", batnum_str, buffer);
157         }
158 }
159
160 static void battery_read (void)
161 {
162 #ifdef KERNEL_LINUX
163         FILE *fh;
164         char buffer[BUFSIZE];
165         char filename[BUFSIZE];
166         
167         char *fields[8];
168         int numfields;
169
170         int i;
171         int len;
172
173         for (i = 0; i < battery_pmu_num; i++)
174         {
175                 double current = 0.0;
176                 double voltage = 0.0;
177                 double charge  = 0.0;
178
179                 len = snprintf (filename, BUFSIZE, battery_pmu_file, i);
180
181                 if ((len >= BUFSIZE) || (len < 0))
182                         continue;
183
184                 if ((fh = fopen (filename, "r")) == NULL)
185                         continue;
186
187                 while (fgets (buffer, BUFSIZE, fh) != NULL)
188                 {
189                         numfields = strsplit (buffer, fields, 8);
190
191                         if (numfields < 3)
192                                 continue;
193
194                         if (strcmp ("current", fields[0]) == 0)
195                                 current = atof (fields[2]) / 1000;
196                         else if (strcmp ("voltage", fields[0]) == 0)
197                                 voltage = atof (fields[2]) / 1000;
198                         else if (strcmp ("charge", fields[0]) == 0)
199                                 charge = atof (fields[2]) / 1000;
200                 }
201
202                 if ((current != 0.0) || (voltage != 0.0) || (charge != 0.0))
203                         battery_submit (i, current, voltage, charge);
204
205                 fclose (fh);
206                 fh = NULL;
207         }
208
209         if (access ("/proc/acpi/battery", R_OK | X_OK) == 0)
210         {
211                 /*
212                  * [11:00] <@tokkee> $ cat /proc/acpi/battery/BAT1/state
213                  * [11:00] <@tokkee> present:                 yes
214                  * [11:00] <@tokkee> capacity state:          ok
215                  * [11:00] <@tokkee> charging state:          charging
216                  * [11:00] <@tokkee> present rate:            1724 mA
217                  * [11:00] <@tokkee> remaining capacity:      4136 mAh
218                  * [11:00] <@tokkee> present voltage:         12428 mV
219                  */
220                 syslog (LOG_DEBUG, "Found directory `/proc/acpi/battery'");
221         }
222 #endif /* KERNEL_LINUX */
223 }
224 #else
225 # define battery_read NULL
226 #endif /* BATTERY_HAVE_READ */
227
228 void module_register (void)
229 {
230         plugin_register (MODULE_NAME, battery_init, battery_read, NULL);
231         plugin_register ("battery_current", NULL, NULL, battery_current_write);
232         plugin_register ("battery_voltage", NULL, NULL, battery_voltage_write);
233         plugin_register ("battery_charge",  NULL, NULL, battery_charge_write);
234 }
235
236 #undef BUFSIZE
237 #undef MODULE_NAME