00001
00034 #include "alarmserverconnector.h"
00035
00036 #include <iostream>
00037 #include <stdexcept>
00038 #include <vector>
00039
00040 #ifndef NOTUSELIBNOTIFY
00041 #include <glib-2.0/glib.h>
00042 #include <libnotify/notification.h>
00043 #include <libnotify/notify.h>
00044 #endif
00045
00046 #include "alarmconfiguration.h"
00047 #include "beedo.h"
00048 #include "cmsclient.h"
00049 #include "emailsender.h"
00050 #include "exceptionhandler.h"
00051 #include "flashlight.h"
00052
00053 using namespace AlarmNotifications;
00054
00055 AlarmServerConnector::AlarmServerConnector ( const bool desktopVersion, const bool activateBeedo )
00056 : _desktopVersion ( desktopVersion ),
00057 _activateBeedo ( activateBeedo ),
00058 _cmsclient ( *this ),
00059 _runwatcher ( true ),
00060 _flashlighton ( false ),
00061 _watcher ( boost::bind ( &AlarmServerConnector::startWatcher, this ) ),
00062 _flashlightthread ( boost::bind ( &AlarmServerConnector::operateFlashLight, this ) ),
00063 _oldestAlarm ( noAlarmActive )
00064 {
00065 if ( !_desktopVersion && _activateBeedo )
00066 throw std::logic_error ( "The \"beedo\" optoacoustic alarm can only be used in desktop mode!" );
00067 #ifndef NOTUSELIBNOTIFY
00068 notify_init ( "DCS Alarm System" );
00069 #endif
00070 }
00071
00072 AlarmServerConnector::~AlarmServerConnector()
00073 {
00074 _runwatcher = false;
00075 _watcher.join();
00076 _flashlightthread.join();
00077 #ifndef NOTUSELIBNOTIFY
00078 notify_uninit();
00079 #endif
00080 }
00081
00082 void AlarmServerConnector::notifyStatusChange ( const AlarmStatusEntry status )
00083 {
00084 boost::lock_guard<boost::mutex> concurrencylock ( _statusmapmutex );
00085 const std::string& pvname = status.getPVName();
00086 auto entry = _statusmap.find ( pvname );
00087 if ( checkSeverityString ( status.getSeverity() ) )
00088 {
00089 if ( entry != _statusmap.end() )
00090 _statusmap.erase ( entry );
00091 }
00092 else
00093 {
00094 if ( entry == _statusmap.end() )
00095 _statusmap.insert ( std::pair<std::string, AlarmStatusEntry> ( pvname, status ) );
00096 else
00097 ( *entry ).second.update ( status );
00098 if ( _oldestAlarm == noAlarmActive )
00099 _oldestAlarm = status.getTriggerTime();
00100 }
00101 }
00102
00103 bool AlarmServerConnector::checkSeverityString ( const std::string& severity )
00104 {
00105 if ( severity == "OK" )
00106 return true;
00107 if ( severity.substr ( severity.length()-4, 4 ) == "_ACK" )
00108 return true;
00109 return false;
00110 }
00111
00112 void AlarmServerConnector::startWatcher()
00113 {
00114 while ( _runwatcher )
00115 {
00116 sleep ( 1 );
00117 checkStatusMap();
00118 }
00119 }
00120
00121 void AlarmServerConnector::checkStatusMap()
00122 {
00123 boost::lock_guard<boost::mutex> concurrencylock ( _statusmapmutex );
00124 if ( _statusmap.size() == 0 && _oldestAlarm != noAlarmActive )
00125 {
00126 _oldestAlarm = noAlarmActive;
00127 if ( _activateBeedo )
00128 Beedo::stop();
00129 }
00130
00131
00132 if (
00133 _statusmap.size() != 0
00134 && _oldestAlarm + AlarmConfiguration::instance().getDesktopNotificationTimeout() <= std::time ( nullptr )
00135 )
00136 {
00137 prepareDesktopNotification();
00138 if ( _activateBeedo )
00139 Beedo::start();
00140 }
00141 if (
00142 _statusmap.size() != 0
00143 && _oldestAlarm + AlarmConfiguration::instance().getEMailNotificationTimeout() <= std::time ( nullptr )
00144 )
00145 prepareEMailNotification();
00146 }
00147
00148 void AlarmServerConnector::operateFlashLight()
00149 {
00150 if ( _desktopVersion )
00151 return;
00152 while ( _runwatcher )
00153 {
00154 sleep ( 1 );
00155 if (
00156 !_flashlighton
00157 && _statusmap.size() != 0
00158 && _oldestAlarm + AlarmConfiguration::instance().getLaboratoryNotificationTimeout() <= std::time ( nullptr )
00159 )
00160 switchFlashLightOn();
00161 if ( _flashlighton && _statusmap.size() == 0 )
00162 switchFlashLightOff();
00163 }
00164 }
00165
00166 void AlarmServerConnector::switchFlashLightOn()
00167 {
00168 if ( AlarmConfiguration::instance().getLaboratoryNotificationTimeout() == 0 )
00169 return;
00170 _flashlighton = true;
00171 std::cout << "Flash light on!" << std::endl;
00172 FlashLight::switchOn();
00173 }
00174
00175 void AlarmServerConnector::switchFlashLightOff()
00176 {
00177 if ( AlarmConfiguration::instance().getLaboratoryNotificationTimeout() == 0 )
00178 return;
00179 _flashlighton = false;
00180 std::cout << "Flash light off!" << std::endl;
00181 FlashLight::switchOff();
00182 }
00183
00184 void AlarmServerConnector::prepareDesktopNotification()
00185 {
00186 if ( AlarmConfiguration::instance().getDesktopNotificationTimeout() == 0 )
00187 return;
00188 std::vector<AlarmStatusEntry> alarmsToUse;
00189 for ( auto i = _statusmap.begin(); i != _statusmap.end(); i++ )
00190 {
00191 if ( ( *i ).second.getTriggerTime() + AlarmConfiguration::instance().getDesktopNotificationTimeout() <= std::time ( nullptr ) )
00192 {
00193 if ( ! ( *i ).second.getDesktopNotificationSent() )
00194 {
00195 ( *i ).second.setDesktopNotificationSent ( true );
00196 alarmsToUse.push_back ( AlarmStatusEntry ( ( *i ).second ) );
00197 }
00198 }
00199 }
00200 if ( alarmsToUse.size() > 0 )
00201 {
00202 boost::thread send ( boost::bind ( &AlarmServerConnector::sendDesktopNotification, this, std::move ( alarmsToUse ) ) );
00203 send.detach();
00204 }
00205 }
00206
00207 void AlarmServerConnector::sendDesktopNotification ( const std::vector<AlarmStatusEntry> alarm )
00208 {
00209 std::string alarmtext = "Alarm on this/these PV(s):\n";
00210 for ( auto i = alarm.begin(); i != alarm.end(); i++ )
00211 {
00212 alarmtext += ( *i ).getPVName() + "\n";
00213 }
00214 #ifndef NOTUSELIBNOTIFY
00215 NotifyNotification* n = notify_notification_new (
00216 "Detector Alarm",
00217 alarmtext.c_str(),
00218 "dialog-warning"
00219 );
00220 notify_notification_set_timeout ( n, NOTIFY_EXPIRES_NEVER );
00221 notify_notification_set_urgency ( n, NOTIFY_URGENCY_CRITICAL );
00222 GError* showerror = nullptr;
00223 notify_notification_show ( n, &showerror );
00224 g_object_unref ( G_OBJECT ( n ) );
00225 #else
00226 std::string command = "notify-send -u critical -t 0 -i dialog-warning 'Detector Alarm' ";
00227 command += std::string ( "'" );
00228 command += alarmtext;
00229 command += std::string ( "'" );
00230 system ( command.c_str() );
00231 #endif
00232 }
00233
00234 void AlarmServerConnector::prepareEMailNotification()
00235 {
00236 if ( _desktopVersion )
00237 return;
00238 if ( AlarmConfiguration::instance().getEMailNotificationTimeout() == 0 )
00239 return;
00240 std::vector<AlarmStatusEntry> alarmsToUse;
00241 for ( auto i = _statusmap.begin(); i != _statusmap.end(); i++ )
00242 {
00243
00244
00245 if ( ! ( *i ).second.getEmailNotificationSent() )
00246 {
00247 ( *i ).second.setEmailNotificationSent ( true );
00248 alarmsToUse.push_back ( AlarmStatusEntry ( ( *i ).second ) );
00249 }
00250
00251 }
00252 if ( alarmsToUse.size() > 0 )
00253 {
00254 boost::thread send ( boost::bind ( &AlarmServerConnector::sendEMailNotification, this, std::move ( alarmsToUse ) ) );
00255 send.detach();
00256 }
00257 }
00258
00259 void AlarmServerConnector::sendEMailNotification ( const std::vector<AlarmStatusEntry> alarm )
00260 {
00261 EMailSender::sendAlarmNotification ( alarm );
00262 }
00263
00264 size_t AlarmServerConnector::getNumberOfAlarms() const noexcept
00265 {
00266 return _statusmap.size();
00267 }