more G-Labs products

Author Topic: ACPUPSD support  (Read 9018 times)

December 15, 2014, 10:41:32 PM
Read 9018 times

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
Has anyone looked into adding support for any UPS's in HG?  I am about to hook an APC brand UPS up to the Raspi and will be using apcupsd to handle communication.  I envision having HG emailing or texting me when power goes down and ideally when it comes back online.  If no one has looked into it yet, I'll see what I can come up with after playing with apcupsd a bit this evening.  I'm assuming it should be possible one way or another.

December 16, 2014, 12:45:05 AM
Reply #1

drpepper

  • *
  • Information
  • Newbie
  • Posts: 23
Good idea. Going to do it via the CGIs or apcaccess polling or something else?

December 16, 2014, 01:34:25 AM
Reply #2

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
I'm not sure now.  I reviewed the manual for apcapud and it already can email/text when the power fails by modifying the script (which may need tweaking anyway).  I may try to get the events broadcast in such a way that HG sees them so that if someone wants to make a widget for visualization, they'd be set.  I'll have to verify that my UPS works with things first, but it looks very promising!

December 16, 2014, 07:41:51 AM
Reply #3

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
I got apcupsd installed and working.  I then tried to install the CGI component so I could query data from HG.  The issue I ran into is that the CGI interface uses apache, which is not installed on the HG raspi image.  I could install it, but I'm concerned that it will interfere with whatever web server hg uses.

I'm going to run more tests on apcupsd to verify that it can shut the raspi down correctly before I spend much time configuring it with hg.  I assume it will be fine, but I'd like to be sure.  Oh, one note for those considering using apcupsd.  If you install it and plug in your ups without properly configuring it, you may break other things.  My system was up and responsive but was not capable of sending x10 commands to the cm15a.  Once configured, it seems to run correctly.

December 16, 2014, 11:28:31 AM
Reply #4

drpepper

  • *
  • Information
  • Newbie
  • Posts: 23
I would want to minimize the overhead if it's running on a Pi, so no apache. I would also try to avoid making users alter their configuration too much. For a quick and dirty, I wouldn't object to polling apcaccess via exec or io events but there could be a cleaner option.

According to the docs apcupsd events will "also generate a call to /etc/apcupsd/apccontrol which in turn will call any scripts you have placed in the /etc/apcupsd directory". So you place your script in that dir, have it curl the HG /api and implement a webservice call received method in your program code to receive the call from your script, parse the event and call any actions you want in HG.

I've got a spare APC to test with, just not the time right now  :-[ Let me know how you get along and I'll have time over Christmas break to help or make a widget or something  :)

December 16, 2014, 02:37:10 PM
Reply #5

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
It took me several months to get up to speed on the c# implementation within HG.  Not being a c# programmer and not touching c since school, it was nice to learn something new.  I'll give the webservice class a reviews and hopefully come up with something.  I really didn't want to install a new web server since one is already running.  I really don't even want to run a second web page since it's really not needed.  I envision using HG for visualization of power (if at all).  Realistically, I could have apcconrtol call a script that emails me, so technically hg isn't needed.  It would be nice to have a widget in my dashboard that shows the basic stats though (number of power outages/brown outs, time on battery, battery charge, line voltage, etc).  But, I'm not sure how easy .json will be to pick up.

December 17, 2014, 06:37:54 PM
Reply #6

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
It looks like the best approach for obtaining voltage/battery %/etc might be to create a script that calls "sudo apcaccess status" and then parses it for important info for HG to use on a given interval (60 or 300 seconds probably).  As for power failures and other critical events, it's probably best to have apccontrol call a HG with a string of what the error is.  Then, based on the error, HG can send an email/text.

One question.  If apcupsd needs to shut down the system, would it be good to stop HG?  Gene mentioned in another thread that it's better to restart the service via the button in the maintenance section so that HG has time to write values.  Is that really needed?

December 18, 2014, 07:29:21 AM
Reply #7

drpepper

  • *
  • Information
  • Newbie
  • Posts: 23
Just an option, you can always call Program.Quit() in your event handler that's called if you're notified of a power outage, but if your system is doing a clean shutdown/halt then it will just call 'service homegenie stop' anyway which will perform the flush writes anyway. So if Program.Quit() gives you the warm fuzzies it's an option, otherwise `shutdown -h now`just before battery death.

December 18, 2014, 05:01:04 PM
Reply #8

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
I'm stuck on step one of communicating between apcupsd and HG.  I know that the daemon can run scripts which can then call anything I want (e.g., call a HG page), but I don't know what I would do in HG to set up a command for the daemon to call.  I know about module commands, but it seems like it would be better to have the daemon call something referencing a script directly.  There are a couple functions that seem designed for this, but I don't have an example of them in use.

http://www.homegenie.it/docs/doxy/d9/d20/class_home_genie_1_1_automation_1_1_scripting_1_1_tcp_client_helper.html

OnStringReceived
OnMessageReceived

I was originally looking at the NetHelper class

http://www.homegenie.it/docs/doxy/d1/d60/class_home_genie_1_1_automation_1_1_scripting_1_1_net_helper.html

But, it looks like that is more intended to pull content rather than listen for connections.  Can anyone help me get started?

December 18, 2014, 06:11:05 PM
Reply #9

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
Perhaps I'm going about this wrong.  Maybe I should just be using  a WebServiceCall Recieved:

http://www.homegenie.it/docs/doxy/d4/dd7/class_home_genie_1_1_automation_1_1_scripting_1_1_events_helper.html#a58515455945c35783cde47d21f844663

It looks like that would allow me to define an event that could be called from apcupsd.  I could do something like this in HG:


Code: [Select]
When.WebServiceCallReceived( "ups.event", (args) =>
{
var returnstring = "";
if (args == "power.off")
{
SendMessage( recipients, "Power out", "A power outage has been detected at " + DateTime.Now.ToString() + ".  HomeGenie is shutting down now.")
}
else if (args == "power.on")
{
SendMessage( recipients, "Power restored", "Power has been restored at " + DateTime.Now.ToString() + ".  HomeGenie is back up and running.")
}

return 0;
});

Then, I'd just need to add an entry to the apccontrol script that makes a call to:

Code: [Select]
http://<hg_server_address>/api/ups.event/power.offor

Code: [Select]
http://<hg_server_address>/api/ups.event/power.on
Does that look right?  I'd still need to figure out poling of the apcaccess status message within HG or writing a shell script to parse it first.

December 18, 2014, 08:37:33 PM
Reply #10

drpepper

  • *
  • Information
  • Newbie
  • Posts: 23
Yep! That's what I was referring to by "have it curl the HG /api and implement a webservice call received method in your program code"

Though I believe your args processing is off. args will be everything after /api/ so your if statement would not match.

You could match the whole thing 'ups.event/power.off' or split the args string and test them individually like
Code: [Select]
When.WebServiceCallReceived( "ups.event", (args) =>
{
string[] reqs = ((string)args).split('/');
string domain = reqs[0];
string event = reqs[1];
string device = reqs[2];

if (event == "power.off")

December 18, 2014, 09:26:01 PM
Reply #11

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
Great, thanks for that!

December 19, 2014, 04:19:41 AM
Reply #12

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
The compiler was really unhappy with using your code.  I haven't used input arguments before, so I'm struggling with getting it to work.  I went back to my original code and tried manually connecting to HG with a web browser and the code never seemed to run.  Not sure what I did wrong at the moment though.

December 19, 2014, 06:57:04 AM
Reply #13

drpepper

  • *
  • Information
  • Newbie
  • Posts: 23
Hi friend, try something like this:
Code: [Select]
When.WebServiceCallReceived( "Ups.Event", (args) =>
{
  string[] reqs = ((string)args).Split('/');
  if (reqs[1] == "Power.Off"){
    Program.Notify("UPS Event","Uh oh.");
  }
  return null;
});
Program.GoBackground();

Where it is requested with:

http://<HG>/api/Ups.Event/Power.Off/0

EDIT: Attach hgx for even easier testing  8)
« Last Edit: December 19, 2014, 07:04:56 AM by drpepper »

December 19, 2014, 05:53:29 PM
Reply #14

bkenobi

  • *****
  • Information
  • Global Moderator
  • Posts: 1525
<Massive face palm>   :o

The reason my code failed was because I had a lowercase "s" in the "Split" command.  I had to copy your working code next to mine and it still took ~5 minutes to see it.