From: Arjen Baart Date: Tue, 31 Mar 2020 14:17:24 +0000 (+0200) Subject: Added configuration and logging for lightcontrol X-Git-Url: http://www.andromeda.nl/gitweb/?a=commitdiff_plain;h=e9552145aed4fd4f43a24adee8f82381de7e9511;p=wakeup.git Added configuration and logging for lightcontrol --- diff --git a/configure.ac b/configure.ac index 3dabdf3..081ba58 100644 --- a/configure.ac +++ b/configure.ac @@ -18,6 +18,25 @@ AC_CHECK_LIB([ACL], [Now]) AC_CHECK_LIB([Tachyon], [main]) # FIXME: Replace `main' with a function in `-lrt': AC_CHECK_LIB([rt], [main]) +# FIXME: Replace `main' with a function in `-lpthread': +AC_CHECK_LIB([pthread], [main]) + + +AC_PATH_PROG(XML_CONFIG,xml2-config,no) + +if test $XML_CONFIG = "no" +then + echo "XML library not found (see http://xmlsoft.org/)." + exit 1; +fi + +XML_CFLAGS=`$XML_CONFIG --cflags` +XML_LFLAGS=`$XML_CONFIG --libs` +AC_CHECK_LIB(xml2, xmlParseFile) + + +CXXFLAGS="$CXXFLAGS $XML_CFLAGS -Wall" +LDFLAGS="$LDFLAGS $XML_LFLAGS" # Checks for header files. AC_CHECK_HEADERS([fcntl.h stdlib.h unistd.h]) diff --git a/doc/design.xml b/doc/design.xml index 9aef045..e531d81 100644 --- a/doc/design.xml +++ b/doc/design.xml @@ -344,16 +344,27 @@ The wakeup times are specified like calendar events, possibly with a recurrence Elements in an event are: Label - Action Start time Recurrence pattern Number of recurrences End time + Action sequence A recurrence pattern can be specified with a number of days, weeks or months as well as a set of weekdays. A set of weekdays implies the recurrence will be weekly. The action for an event can be a light sequence or a curtain control. + +When an event triggers, a sequence of actions is executed. +Possible actions: + + Light control + Curtain control + Cancel an event + Create a sunrise or sunset event + Wait a while + + An event is read from an XML element or created dynamically, for example calculated from the time of sunrise. diff --git a/doc/wakeup-classes.svg b/doc/wakeup-classes.svg index 950d04b..054b46d 100644 --- a/doc/wakeup-classes.svg +++ b/doc/wakeup-classes.svg @@ -26,7 +26,7 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.86772068" - inkscape:cx="255.00379" + inkscape:cx="140.42641" inkscape:cy="579.0815" inkscape:document-units="mm" inkscape:current-layer="layer1" @@ -272,5 +272,16 @@ inkscape:connector-curvature="0" inkscape:connection-start="#path4528" inkscape:connection-end="#rect5098" /> + execute diff --git a/doc/wakeup.svg b/doc/wakeup.svg index 49e786f..7c1be91 100644 --- a/doc/wakeup.svg +++ b/doc/wakeup.svg @@ -26,7 +26,7 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.98994949" - inkscape:cx="159.49246" + inkscape:cx="281.56296" inkscape:cy="798.19494" inkscape:document-units="mm" inkscape:current-layer="layer1" @@ -44,7 +44,7 @@ image/svg+xml - + @@ -284,6 +284,6 @@ id="tspan4567" x="23.938553" y="140.03242" - style="stroke-width:0.26458332px">Fade lights to desired level or open curtains + style="stroke-width:0.26458332px">Execute action sequence diff --git a/src/Makefile.am b/src/Makefile.am index 59f9787..0507dc3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,8 @@ -bin_PROGRAMS = pwm lightcontrol sunrise read_serial +bin_PROGRAMS = wakeup pwm lightcontrol sunrise read_serial +wakeup_SOURCES = wakeup.cpp event.cpp pwm_SOURCES = pwm.c -lightcontrol_SOURCES = lightcontrol.cpp +lightcontrol_SOURCES = lightcontrol.cpp logging.cpp sunrise_SOURCES = sunrise.cpp read_serial_SOURCES = read_serial.cpp diff --git a/src/action.h b/src/action.h index 8f29894..797ab80 100644 --- a/src/action.h +++ b/src/action.h @@ -1,16 +1,44 @@ -#include -#include -#include +#include + class Action { +protected: + + String parameters; + public: -virtual void execute() = 0; + void set_parameters(String p) + { + parameters = p; + } -} + virtual String command_line(void) + { + return String("no command"); + } +//virtual void execute() = 0; + +}; + +class Lightstep : public Action +{ + virtual String command_line(void) + { + String cmd("lightcontrol "); + cmd += parameters; + return cmd; + } +}; -class Lightstep : Action +class Sleepstep : public Action { -} + virtual String command_line(void) + { + String cmd("sleep "); + cmd += parameters; + return cmd; + } +}; diff --git a/src/event.cpp b/src/event.cpp new file mode 100644 index 0000000..a2f10d8 --- /dev/null +++ b/src/event.cpp @@ -0,0 +1,106 @@ +#include "event.h" + +void Event::FromXML(xml_element x) +{ + std::vector elems; + + elems = x["start"]; + start_time = elems[0].content(); + + elems = x["action"]; + for (unsigned int i = 0; i < elems.size(); i++) + { + add_action(elems[i].content()); + } +} + +String Event::ToXML(void) +{ + String xml_text; + std::list::iterator act; + + xml_text = " \n"; + + xml_text += " "; + xml_text += start_time.format(); + xml_text += "\n"; + + for (act = sequence.begin(); act != sequence.end(); act++) + { + xml_text += " "; + xml_text += (*act)->command_line(); + xml_text += "\n"; + } + xml_text += " \n"; + + return xml_text; +} + +void Event::add_action(String command) +{ + String to_execute, parameters; + int separation; + + separation = command.index(' '); + to_execute = command(0, separation); + parameters = command << separation + 1; + + if (to_execute == "lightcontrol") + { + Lightstep *act; + act = new Lightstep; + + act->set_parameters(parameters); + sequence.push_back(act); + } + else if (to_execute == "sleep") + { + Sleepstep *act; + act = new Sleepstep; + + act->set_parameters(parameters); + sequence.push_back(act); + } +} + +std::list read_alarms(const char filename[]) +{ + std::list collected_alarms; + std::vector alarms; + + xml wakeups; + wakeups.ParseFile(filename); + + xml_element wakeup_tree(wakeups); + + alarms = wakeup_tree["event"]; + + for (unsigned int i = 0; i < alarms.size(); i++) + { + Event alarm("name"); + + alarm.FromXML(alarms[i]); + collected_alarms.push_back(alarm); + } + + return collected_alarms; +} + +String alarms_to_XML(std::list alarms) +{ + String xml_text("\n"); + + xml_text += "\n"; + + std::list::iterator a; + + for (a = alarms.begin(); a != alarms.end(); a++) + { + xml_text += a->ToXML(); + } + + xml_text += "\n"; + return xml_text; +} diff --git a/src/event.h b/src/event.h index ab1214e..b4cdd27 100644 --- a/src/event.h +++ b/src/event.h @@ -1,12 +1,15 @@ +#include +#include +#include #include "action.h" class Event { - String label; - date start_time; - std::list sequence; + String label; + UTC start_time; + std::list sequence; public: @@ -15,5 +18,11 @@ public: label = lbl; } - void FromXML(xmlnode x); -} + void FromXML(xml_element x); + String ToXML(void); + + void add_action(String command); +}; + +std::list read_alarms(const char *filename); +String alarms_to_XML(std::list alarms); diff --git a/src/lightcontrol.cpp b/src/lightcontrol.cpp index a1b13a2..f5c0100 100644 --- a/src/lightcontrol.cpp +++ b/src/lightcontrol.cpp @@ -8,13 +8,17 @@ #include #include #include +#include #include #include #include +#include #include #include +#include #include #include "pwm.h" +#include "logging.h" //#define DEBUG @@ -189,6 +193,25 @@ void light_to_pwm(std::vector &lightlevels) signals[N_COLORS].output = -1; } +// Create a report of light levels for logging and debugging + +std::ostringstream report_lights(std::vector lights) +{ + std::ostringstream report; + lvl_ptr p; + + p = find_level(lights, RED); + report << "red=" << p->level << " "; + p = find_level(lights, GREEN); + report << "green=" << p->level << " "; + p = find_level(lights, BLUE); + report << "blue=" << p->level << " "; + p = find_level(lights, WHITE); + report << "white=" << p->level; + + return report; +} + /* * Fade the lights from the start level to the end level in the specified fade time. */ @@ -247,8 +270,39 @@ void lightfade(std::vector start_lvl, std::vector end_ remove("lightcontrol.run"); } +String parent_command(void) +{ + pid_t parent_pid; + String parent_comm; + + parent_pid = getppid(); + + String parent_proc_filename("/proc/"); + parent_proc_filename += String(parent_pid) + "/comm"; + + std::ifstream parent_proc_file(parent_proc_filename); + parent_proc_file >> parent_comm; + + return parent_comm; +} + + int main(int argc, char *argv[]) { + configuration cfg; + String logdir; + + cfg.read("lightcontrol"); + logdir = cfg.find_parameter("logging", "destination"); + if (logdir == "") + { + logdir = "."; // default to current dir + } + logstream log(logdir + "/lightcontrol.log"); + + String start_message("lightcontrol started by "); + + log << start_message + parent_command(); int fade_time = 0; bool change_lights = false; @@ -345,8 +399,18 @@ int main(int argc, char *argv[]) } } + if (change_lights) { + std::ostringstream report; + + report << "Changing light levels to: "; + report << report_lights(desired_levels).str(); + if (fade_time != 0) + { + report << ", fading in " << fade_time << " seconds"; + } + log << report.str().c_str(); lightfade(lightlevels, desired_levels, fade_time); } } diff --git a/src/logging.cpp b/src/logging.cpp new file mode 100644 index 0000000..65241dc --- /dev/null +++ b/src/logging.cpp @@ -0,0 +1,26 @@ +#include + +#include "logging.h" + + +logstream & logstream::operator << (const char *msg) +{ + UTC timestamp; + + timestamp = Now(); + + destination << timestamp << ": " << msg << "\n"; + + return *this; +} + +logstream & logstream::operator << (const String &msg) +{ + UTC timestamp; + + timestamp = Now(); + + destination << timestamp << ": " << msg << "\n"; + + return *this; +} diff --git a/src/logging.h b/src/logging.h new file mode 100644 index 0000000..8998cf9 --- /dev/null +++ b/src/logging.h @@ -0,0 +1,17 @@ +#include +#include + +class logstream : public std::ofstream +{ + std::ofstream destination; + +public: + + logstream(const char * filename) + { + destination.open(filename, std::ios_base::app); + } + + logstream & operator << (const char *msg); + logstream & operator << (const String &msg); +}; diff --git a/src/wakeup.cpp b/src/wakeup.cpp new file mode 100644 index 0000000..7dd048f --- /dev/null +++ b/src/wakeup.cpp @@ -0,0 +1,10 @@ +#include "event.h" + +int main() +{ + std::list set_alarms; + + set_alarms = read_alarms("wakeup_alarms.xml"); + + std::cout << alarms_to_XML(set_alarms); +} diff --git a/test/Makefile.am b/test/Makefile.am index 017067c..f1a54f3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1 +1,7 @@ -TESTS = lightctrl lightctrl-oor lightctrl-fade +TESTS = lightctrl lightctrl-oor lightctrl-fade $(check_PROGRAMS) check_output + +AM_CPPFLAGS = -I../src +LDADD = -lTachyon -lACL +check_PROGRAMS = wakeup_load_events + +wakeup_load_events_SOURCES = wakeup_load_events.cpp ../src/event.cpp diff --git a/test/check_output b/test/check_output new file mode 100755 index 0000000..62f828f --- /dev/null +++ b/test/check_output @@ -0,0 +1,17 @@ +#!/bin/bash + +STATUS=0 + +for output in *.exp +do + logfile=`basename $output .exp` + logfile=${logfile}.log + echo "Comparing $output with $logfile" + diff $output $logfile + RESULT=$? + if [ $STATUS == 0 ] + then + STATUS=${RESULT} + fi +done +exit $STATUS diff --git a/test/lightcontrol.conf b/test/lightcontrol.conf new file mode 100644 index 0000000..cf01efd --- /dev/null +++ b/test/lightcontrol.conf @@ -0,0 +1,9 @@ + + + + file + . + 0 + + + diff --git a/test/lightctrl-fade.exp b/test/lightctrl-fade.exp new file mode 100644 index 0000000..525364a --- /dev/null +++ b/test/lightctrl-fade.exp @@ -0,0 +1,19 @@ +0 0 0 0 +0 0 0 0 +0 0 0 0 +0 1 0 1 +3 4 2 4 +5 7 3 7 +8 11 5 11 +10 14 7 14 +13 18 9 18 +15 21 10 21 +18 24 12 24 +21 28 14 28 +23 31 15 31 +26 35 17 35 +28 38 19 38 +Receiving message. +The message is A10.000000. +30 40 20 40 +PASS lightctrl-fade (exit status: 0) diff --git a/test/lightctrl-oor.exp b/test/lightctrl-oor.exp new file mode 100644 index 0000000..228ffb1 --- /dev/null +++ b/test/lightctrl-oor.exp @@ -0,0 +1,7 @@ +Set light to (R G B W) 0 0 0 50 +Light levels are 0 0 0 50 +Set light to (R G B W) 200 0 0 50 +Light levels are 100 0 0 50 +Set light to (R G B W) 100 0 0 -1 +Light levels are 100 0 0 0 +PASS lightctrl-oor (exit status: 0) diff --git a/test/wakeup-01.xml b/test/wakeup-01.xml new file mode 100644 index 0000000..eb4e8f8 --- /dev/null +++ b/test/wakeup-01.xml @@ -0,0 +1,11 @@ + + + + 2020-03-22 06:00 + lightcontrol -r 100 -f 200 + lightcontrol -g 100 -f 200 + lightcontrol -w 100 -f 200 + sleep 600 + lightcontrol -r 0 -g 0 -w 0 -f 200 + + diff --git a/test/wakeup_load_events.cpp b/test/wakeup_load_events.cpp new file mode 100644 index 0000000..219bd1b --- /dev/null +++ b/test/wakeup_load_events.cpp @@ -0,0 +1,10 @@ +#include "event.h" + +int main() +{ + std::list set_alarms; + + set_alarms = read_alarms("wakeup-01.xml"); + + std::cout << alarms_to_XML(set_alarms); +} diff --git a/test/wakeup_load_events.exp b/test/wakeup_load_events.exp new file mode 100644 index 0000000..1acff55 --- /dev/null +++ b/test/wakeup_load_events.exp @@ -0,0 +1,12 @@ + + + + 2020-03-22 06:00:00 + lightcontrol -r 100 -f 200 + lightcontrol -g 100 -f 200 + lightcontrol -w 100 -f 200 + sleep 600 + lightcontrol -r 0 -g 0 -w 0 -f 200 + + +PASS wakeup_load_events (exit status: 0)