---
title: Monitoring an APC Back-UPS With openHAB 2
date: 2017-03-18
url: https://aaron.cc/integrating-my-apc-ups-into-openhab-2/
---


openHAB doesn’t have a binding for APC UPS devices. Luckily, there are other ways to integrate them into your openHAB setup.

In the following, I’m describing how the *exec* binding can be used to regularly poll the UPS status using the *apcaccess* command-line utility.

The result will look somehow like this:

{{< img

  src="images/openHAB-APC-Screenshots-Kopie.jpg"
>}}

I’m using a [APC Back-UPS BX 700VA](https://www.amazon.de/APC-Back-UPS-BX-Unterbrechungsfreie-Stromversorgung/dp/B00T7BYRCK) here—a relatively cheap model with Schuko outlets and a USB connector.

## Prerequisites

- APC Back-UPS connected and configured (the *apcaccess* command needs to work)
- Working openHAB 2 installation

## Configuration

We’ll need to add a binding, a thing, various items, and finally an entry in the sitemap.

### Bindings

As aforementioned, I’m using the *exec* binding to poll the status of the *apcaccess* command-line utility on a regular basis. To install the *exec* binding, add `exec` to the binding list in `services/addons.cfg`.

**Example:**

```
# A comma-separated list of bindings to install (e.g. "sonos,knx,zwave")
binding = exec
```

### Things

To make the UPS status available to openHAB, create a new file called `apc.things` in your `things` directory and insert the following line:

```
Thing exec:command:apc [command="/sbin/apcaccess -u", interval=5, timeout=2, autorun=false]
```

The `-u` parameter will suppress any units (volts, percent, seconds, etc.) This makes parsing of the output much easier.

**Note:** The command above assumes that the *apcaccess* command-line utility is located in `/sbin/`. Adjust this path if necessary.

### Items

Create a new file called `apc.items` in your `items` directory and insert the following contents:

```
String APC_Raw { channel="exec:command:apc:output" }

Group gAPC

String      APC_APC         (gAPC)
DateTime    APC_DATE        (gAPC)
String      APC_HOSTNAME    (gAPC)
String      APC_VERSION     (gAPC)
String      APC_UPSNAME     (gAPC)
String      APC_CABLE       (gAPC)
String      APC_DRIVER      (gAPC)
String      APC_UPSMODE     (gAPC)
DateTime    APC_STARTTIME   (gAPC)
String      APC_MODEL       (gAPC)
String      APC_STATUS      (gAPC)
Number      APC_LINEV       (gAPC)
Number      APC_LOADPCT     (gAPC)
Number      APC_BCHARGE     (gAPC)
Number      APC_TIMELEFT    (gAPC)
Number      APC_MBATTCHG    (gAPC)
Number      APC_MINTIMEL    (gAPC)
Number      APC_MAXTIME     (gAPC)
String      APC_SENSE       (gAPC)
Number      APC_LOTRANS     (gAPC)
Number      APC_HITRANS     (gAPC)
Number      APC_ALARMDEL    (gAPC)
Number      APC_BATTV       (gAPC)
String      APC_LASTXFER    (gAPC)
Number      APC_NUMXFERS    (gAPC)
DateTime    APC_XONBATT     (gAPC)
Number      APC_TONBATT     (gAPC)
Number      APC_CUMONBATT   (gAPC)
DateTime    APC_XOFFBATT    (gAPC)
String      APC_SELFTEST    (gAPC)
String      APC_STATFLAG    (gAPC)
String      APC_SERIALNO    (gAPC)
DateTime    APC_BATTDATE    (gAPC)
Number      APC_NOMINV      (gAPC)
Number      APC_NOMBATTV    (gAPC)
Number      APC_NOMPOWER    (gAPC)
String      APC_FIRMWARE    (gAPC)
```

The first item called `APC_Raw` holds the full output of the *apcaccess* utility. The other items don’t do anything yet—in the next step, we will create a rule to parse the output and assign values the individual items. *The group gAPC is required by the rule, so don’t forget to specify it here.*

**Note:** If you have a different model than I have, this list might not be 100% correct. Run `apcaccess` to get a list of parameters available for your UPS, and adjust the list accordingly.

### Rules

Create a new file called `apc.rules` in your `rules` directory and insert the following contents:

```
import java.io.BufferedReader
import java.io.StringReader
import java.util.Calendar
import java.text.SimpleDateFormat
import java.text.ParseException

rule "APC: Parse raw output from command-line tool"
when
	Item APC_Raw changed
then
	var output = APC_Raw.state.toString
	var String line
	var String[] buffer
	var String value
	var bufReader = new BufferedReader(new StringReader(output))
	var Calendar cal = Calendar.getInstance()
	var formatStrings = newArrayList('yyyy-MM-dd HH:mm:ss Z', 'yyyy-MM-dd')
		
	while((line = bufReader.readLine()) != null) {
		buffer = line.split(':', 2)
		for (var i = 0; i < 2; i++) {
			buffer.set(i, buffer.get(i).trim())
    	}
    	
    	// check if there’s an item for this key (e.g. APC_STARTTIME)
    	var item = gAPC.members.findFirst[name.equals("APC_" + buffer.get(0))]

		if (item != null) {
			value = buffer.get(1)
			
			// DateTime item: try to parse date
			if (item.type == 'DateTime') {
				var succeeded = false
				for (String formatString : formatStrings) {
					try {
						if (!succeeded) { // no `break` statement in openHAB :(
							cal.setTime(new SimpleDateFormat(formatString).parse(value))
							item.postUpdate(new DateTimeType(cal).toString)
							succeeded = true
						}
					} catch (ParseException e) { }
				}
			// String or Number: just update the value
			} else {
				item.postUpdate(value)	
			}
		}
	}
	
end
```

Whenever `APC_Raw` changes, this rule will process the command’s output and will fill in the individual items with the correctly parsed values (these can be of type `String`, `Number`, or `DateTime`).

### Sitemap

Finally, to expose these values, create an additional entry in your sitemap. If you’re using the default sitemap, open the file `sitemaps/default.sitemap` and add the following:

```
sitemap default label="Home" {

	// …

	Frame label="System Status" {
		Text label="UPS [%s]" item=APC_STATUS valuecolor=[APC_STATUS=="ONBATT"="#FF0000",APC_STATUS=="ONLINE"="#008000"] {
			Text item=APC_MODEL label="Model [%s]"
			Text item=APC_STATUS label="Status [%s]" valuecolor=[APC_STATUS=="ONBATT"="#FF0000",APC_STATUS=="ONLINE"="#008000"]
			Text item=APC_STARTTIME label="Start Time [%1$td/%1$tm/%1$ty %1$tH:%1$tM]"
			Text item=APC_LOADPCT label="Load [%.1f %%]"
			Text item=APC_TIMELEFT label="Time Left [%.1f min]"
			Text item=APC_LINEV label="Line Voltage [%.1f V]"
			Text item=APC_BATTV label="Battery Voltage [%.1f V]"
			Text item=APC_BATTDATE label="Battery Date [%1$td/%1$tm/%1$ty]"
		}
	}
}
```

As you can see, I haven’t added all available values here. Adjust this to your needs.

That’s it!

## Bonus: Push Notification On Power Outage

To get a notification on your mobile device whenever the power fails (and also when it returns), configure the *pushover* binding and add the following rule to your `apc.rules`:

```
rule "APC: Notify power outage/return"
when
	Item APC_STATUS changed
then

	var msg = ''

	if (APC_STATUS.state == "ONLINE") {
		msg = "Power has returned"
	} else if (APC_STATUS.state == "ONBATT") {
		msg = "Power outage detected, remaining battery life: " + APC_TIMELEFT.state + " min"
	}
	
	if (msg != '') {
		logInfo("APC", msg)
		pushover(msg)
	}
end
```

## Further Reading

- <https://community.openhab.org/t/how-to-store-output-from-exec-binding-as-numbers/24556>
- <http://docs.openhab.org/addons/actions/pushover/readme.html>
- <http://www.marcsblog.de/2015/07/pushover-openhab-benachrichtigt-ueber-das-smartphone/> *(German)*
