MythTV  master
zmclient.cpp
Go to the documentation of this file.
1 /*
2  zmclient.cpp
3 */
4 
5 #include <unistd.h>
6 
7 // qt
8 #include <QTimer>
9 
10 //myth
11 #include "mythcontext.h"
12 #include "mythdialogbox.h"
13 #include <mythdate.h>
14 #include "mythmainwindow.h"
15 #include "mythlogging.h"
16 
17 //zoneminder
18 #include "zmclient.h"
19 #include "zmminiplayer.h"
20 
21 // the protocol version we understand
22 #define ZM_PROTOCOL_VERSION "11"
23 
24 #define BUFFER_SIZE (2048*1536*3)
25 
27  : QObject(nullptr),
28  m_retryTimer(new QTimer(this))
29 {
30  setObjectName("ZMClient");
31  connect(m_retryTimer, SIGNAL(timeout()), this, SLOT(restartConnection()));
32 
34 }
35 
37 
39 {
40  if (!m_zmclient)
41  m_zmclient = new ZMClient;
42  return m_zmclient;
43 }
44 
46 {
47  QString zmserver_host;
48  int zmserver_port;
49 
50  zmserver_host = gCoreContext->GetSetting("ZoneMinderServerIP", "");
51  zmserver_port = gCoreContext->GetNumSetting("ZoneMinderServerPort", -1);
52 
53  // don't try to connect if we don't have a valid host or port
54  if (zmserver_host.isEmpty() || zmserver_port == -1)
55  {
56  LOG(VB_GENERAL, LOG_INFO, "ZMClient: no valid IP or port found for mythzmserver");
57  return false;
58  }
59 
60  return ZMClient::get()->connectToHost(zmserver_host, zmserver_port);
61 }
62 
63 bool ZMClient::connectToHost(const QString &lhostname, unsigned int lport)
64 {
65  QMutexLocker locker(&m_socketLock);
66 
67  m_hostname = lhostname;
68  m_port = lport;
69 
70  m_bConnected = false;
71  int count = 0;
72  do
73  {
74  ++count;
75 
76  LOG(VB_GENERAL, LOG_INFO,
77  QString("Connecting to zm server: %1:%2 (try %3 of 2)")
78  .arg(m_hostname).arg(m_port).arg(count));
79  if (m_socket)
80  {
81  m_socket->DecrRef();
82  m_socket = nullptr;
83  }
84 
85  m_socket = new MythSocket();
86 
88  {
89  m_socket->DecrRef();
90  m_socket = nullptr;
91  }
92  else
93  {
94  m_zmclientReady = true;
95  m_bConnected = true;
96  }
97 
98  usleep(999999);
99 
100  } while (count < 2 && !m_bConnected);
101 
102  if (!m_bConnected)
103  {
104  if (GetNotificationCenter())
105  {
106  ShowNotificationError(tr("Can't connect to the mythzmserver") , "MythZoneMinder",
107  tr("Is it running? "
108  "Have you set the correct IP and port in the settings?"));
109  }
110  }
111 
112  // check the server uses the same protocol as us
114  {
115  m_zmclientReady = false;
116  m_bConnected = false;
117  }
118 
119  if (m_bConnected)
121 
122  return m_bConnected;
123 }
124 
125 bool ZMClient::sendReceiveStringList(QStringList &strList)
126 {
127  QStringList origStrList = strList;
128 
129  bool ok = false;
130  if (m_bConnected)
131  ok = m_socket->SendReceiveStringList(strList);
132 
133  if (!ok)
134  {
135  LOG(VB_GENERAL, LOG_NOTICE, "Connection to mythzmserver lost");
136 
138  {
139  LOG(VB_GENERAL, LOG_ERR, "Re-connection to mythzmserver failed");
140  return false;
141  }
142 
143  // try to resend
144  strList = origStrList;
145  ok = m_socket->SendReceiveStringList(strList);
146  if (!ok)
147  {
148  m_bConnected = false;
149  return false;
150  }
151  }
152 
153  // sanity check
154  if (strList.empty())
155  {
156  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
157  return false;
158  }
159 
160  // the server sends "UNKNOWN_COMMAND" if it did not recognise the command
161  if (strList[0] == "UNKNOWN_COMMAND")
162  {
163  LOG(VB_GENERAL, LOG_ERR, "Somethings is getting passed to the server "
164  "that it doesn't understand");
165  return false;
166  }
167 
168  // the server sends "ERROR" if it failed to process the command
169  if (strList[0].startsWith("ERROR"))
170  {
171  LOG(VB_GENERAL, LOG_ERR,
172  QString("The server failed to process the command. "
173  "The error was:- \n\t\t\t%1").arg(strList[0]));
174  return false;
175  }
176 
177  // we should get "OK" from the server if everything is OK
178  return strList[0] == "OK";
179 }
180 
182 {
183  QMutexLocker locker(&m_commandLock);
184 
185  QStringList strList("HELLO");
186  if (!sendReceiveStringList(strList))
187  {
188  LOG(VB_GENERAL, LOG_ERR, QString("Server didn't respond to 'HELLO'!!"));
189 
190  ShowOkPopup(tr("The mythzmserver didn't respond to our request "
191  "to get the protocol version!!"));
192  return false;
193  }
194 
195  // sanity check
196  if (strList.size() < 2)
197  {
198  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
199  return false;
200  }
201 
202  if (strList[1] != ZM_PROTOCOL_VERSION)
203  {
204  LOG(VB_GENERAL, LOG_ERR,
205  QString("Protocol version mismatch (plugin=%1, mythzmserver=%2)")
206  .arg(ZM_PROTOCOL_VERSION).arg(strList[1]));
207 
208  ShowOkPopup(QString("The mythzmserver uses protocol version %1, "
209  "but this client only understands version %2. "
210  "Make sure you are running compatible versions of "
211  "both the server and plugin.")
212  .arg(strList[1]).arg(ZM_PROTOCOL_VERSION));
213  return false;
214  }
215 
216  LOG(VB_GENERAL, LOG_INFO,
217  QString("Using protocol version %1").arg(ZM_PROTOCOL_VERSION));
218  return true;
219 }
220 
222 {
223  // Reset the flag
224  m_zmclientReady = false;
225  m_bConnected = false;
226 
227  // Retry to connect. . . Maybe the user restarted mythzmserver?
229 }
230 
232 {
233  QMutexLocker locker(&m_socketLock);
234 
235  if (m_socket)
237 
238  m_zmclientReady = false;
239  m_bConnected = false;
240 }
241 
243 {
245 
246  m_zmclient = nullptr;
247 
248  if (m_socket)
249  {
250  m_socket->DecrRef();
251  m_socket = nullptr;
252  m_zmclientReady = false;
253  }
254 
255  delete m_retryTimer;
256 }
257 
258 void ZMClient::getServerStatus(QString &status, QString &cpuStat, QString &diskStat)
259 {
260  QMutexLocker locker(&m_commandLock);
261 
262  QStringList strList("GET_SERVER_STATUS");
263  if (!sendReceiveStringList(strList))
264  return;
265 
266  // sanity check
267  if (strList.size() < 4)
268  {
269  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
270  return;
271  }
272 
273  status = strList[1];
274  cpuStat = strList[2];
275  diskStat = strList[3];
276 }
277 
279 {
280  QMutexLocker clocker(&m_commandLock);
281 
282  QStringList strList("GET_MONITOR_STATUS");
283  if (!sendReceiveStringList(strList))
284  return;
285 
286  // sanity check
287  if (strList.size() < 2)
288  {
289  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
290  return;
291  }
292 
293  bool bOK;
294  int monitorCount = strList[1].toInt(&bOK);
295  if (!bOK)
296  {
297  LOG(VB_GENERAL, LOG_ERR,
298  "ZMClient received bad int in getMonitorStatus()");
299  return;
300  }
301 
302  QMutexLocker locker(&m_listLock);
303 
304  for (int x = 0; x < monitorCount; x++)
305  {
306  int monID = strList[x * 7 + 2].toInt();
307 
308  if (m_monitorMap.contains(monID))
309  {
310  Monitor *mon = m_monitorMap.find(monID).value();
311  mon->name = strList[x * 7 + 3];
312  mon->zmcStatus = strList[x * 7 + 4];
313  mon->zmaStatus = strList[x * 7 + 5];
314  mon->events = strList[x * 7 + 6].toInt();
315  mon->function = strList[x * 7 + 7];
316  mon->enabled = (strList[x * 7 + 8].toInt() != 0);
317  }
318  }
319 }
320 
321 static QString stateToString(State state)
322 {
323  QString result = "UNKNOWN";
324 
325  switch (state)
326  {
327  case IDLE:
328  result = "IDLE";
329  break;
330  case PREALARM:
331  result = "PREALARM";
332  break;
333  case ALARM:
334  result = "ALARM";
335  break;
336  case ALERT:
337  result = "ALERT";
338  break;
339  case TAPE:
340  result = "TAPE";
341  break;
342  default:
343  result = "UNKNOWN";
344  }
345 
346  return result;
347 }
348 
350 {
351  QMutexLocker clocker(&m_commandLock);
352 
353  QStringList strList("GET_ALARM_STATES");
354  if (!sendReceiveStringList(strList))
355  return false;
356 
357  // sanity check
358  if (strList.size() < 2)
359  {
360  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
361  return false;
362  }
363 
364  bool bOK;
365  int monitorCount = strList[1].toInt(&bOK);
366  if (!bOK)
367  {
368  LOG(VB_GENERAL, LOG_ERR,
369  "ZMClient received bad int in getAlarmStates()");
370  return false;
371  }
372 
373  QMutexLocker locker(&m_listLock);
374 
375  bool changed = false;
376  for (int x = 0; x < monitorCount; x++)
377  {
378  int monID = strList[x * 2 + 2].toInt();
379  State state = (State)strList[x * 2 + 3].toInt();
380 
381  if (m_monitorMap.contains(monID))
382  {
383  Monitor *mon = m_monitorMap.find(monID).value();
384  if (mon->state != state)
385  {
386  // alarm state has changed for this monitor
387  LOG(VB_GENERAL, LOG_DEBUG,
388  QString("ZMClient monitor %1 changed state from %2 to %3")
389  .arg(mon->name).arg(stateToString(mon->state)).arg(stateToString(state)));
390  mon->previousState = mon->state;
391  mon->state = state;
392  changed = true;
393  }
394  }
395  }
396 
397  return changed;
398 }
399 
400 void ZMClient::getEventList(const QString &monitorName, bool oldestFirst,
401  const QString &date, bool includeContinuous,
402  vector<Event*> *eventList)
403 {
404  QMutexLocker locker(&m_commandLock);
405 
406  eventList->clear();
407 
408  QStringList strList("GET_EVENT_LIST");
409  strList << monitorName << (oldestFirst ? "1" : "0") ;
410  strList << date;
411  strList << (includeContinuous ? "1" : "0") ;
412 
413  if (!sendReceiveStringList(strList))
414  return;
415 
416  // sanity check
417  if (strList.size() < 2)
418  {
419  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
420  return;
421  }
422 
423  bool bOK;
424  int eventCount = strList[1].toInt(&bOK);
425  if (!bOK)
426  {
427  LOG(VB_GENERAL, LOG_ERR, "ZMClient received bad int in getEventList()");
428  return;
429  }
430 
431  // sanity check
432  if ((strList.size() - 2) / 6 != eventCount)
433  {
434  LOG(VB_GENERAL, LOG_ERR,
435  "ZMClient got a mismatch between the number of events and "
436  "the expected number of stringlist items in getEventList()");
437  return;
438  }
439 
440  QStringList::Iterator it = strList.begin();
441  it++; it++;
442  for (int x = 0; x < eventCount; x++)
443  {
444  eventList->push_back(
445  new Event(
446  (*it++).toInt(), /* eventID */
447  *it++, /* eventName */
448  (*it++).toInt(), /* monitorID */
449  *it++, /* monitorName */
450  QDateTime::fromString(*it++, Qt::ISODate), /* startTime */
451  *it++ /* length */));
452  }
453 }
454 
455 void ZMClient::getEventDates(const QString &monitorName, bool oldestFirst,
456  QStringList &dateList)
457 {
458  QMutexLocker locker(&m_commandLock);
459 
460  dateList.clear();
461 
462  QStringList strList("GET_EVENT_DATES");
463  strList << monitorName << (oldestFirst ? "1" : "0") ;
464 
465  if (!sendReceiveStringList(strList))
466  return;
467 
468  // sanity check
469  if (strList.size() < 2)
470  {
471  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
472  return;
473  }
474 
475  bool bOK;
476  int dateCount = strList[1].toInt(&bOK);
477  if (!bOK)
478  {
479  LOG(VB_GENERAL, LOG_ERR,
480  "ZMClient received bad int in getEventDates()");
481  return;
482  }
483 
484  // sanity check
485  if ((strList.size() - 3) != dateCount)
486  {
487  LOG(VB_GENERAL, LOG_ERR,
488  "ZMClient got a mismatch between the number of dates and "
489  "the expected number of stringlist items in getEventDates()");
490  return;
491  }
492 
493  QStringList::Iterator it = strList.begin();
494  it++; it++;
495  for (int x = 0; x < dateCount; x++)
496  {
497  dateList.append(*it++);
498  }
499 }
500 
501 void ZMClient::getFrameList(int eventID, vector<Frame*> *frameList)
502 {
503  QMutexLocker locker(&m_commandLock);
504 
505  frameList->clear();
506 
507  QStringList strList("GET_FRAME_LIST");
508  strList << QString::number(eventID);
509  if (!sendReceiveStringList(strList))
510  return;
511 
512  // sanity check
513  if (strList.size() < 2)
514  {
515  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
516  return;
517  }
518 
519  bool bOK;
520  int frameCount = strList[1].toInt(&bOK);
521  if (!bOK)
522  {
523  LOG(VB_GENERAL, LOG_ERR, "ZMClient received bad int in getFrameList()");
524  return;
525  }
526 
527  // sanity check
528  if ((strList.size() - 2) / 2 != frameCount)
529  {
530  LOG(VB_GENERAL, LOG_ERR,
531  "ZMClient got a mismatch between the number of frames and "
532  "the expected number of stringlist items in getFrameList()");
533  return;
534  }
535 
536  QStringList::Iterator it = strList.begin();
537  it++; it++;
538  for (int x = 0; x < frameCount; x++)
539  {
540  Frame *item = new Frame;
541  item->type = *it++;
542  item->delta = (*it++).toDouble();
543  frameList->push_back(item);
544  }
545 }
546 
547 void ZMClient::deleteEvent(int eventID)
548 {
549  QMutexLocker locker(&m_commandLock);
550 
551  QStringList strList("DELETE_EVENT");
552  strList << QString::number(eventID);
553  sendReceiveStringList(strList);
554 }
555 
556 void ZMClient::deleteEventList(vector<Event*> *eventList)
557 {
558  QMutexLocker locker(&m_commandLock);
559 
560  // delete events in 100 event chunks
561  QStringList strList("DELETE_EVENT_LIST");
562  int count = 0;
563  vector<Event*>::iterator it;
564  for (it = eventList->begin(); it != eventList->end(); ++it)
565  {
566  strList << QString::number((*it)->eventID());
567 
568  if (++count == 100)
569  {
570  sendReceiveStringList(strList);
571  strList = QStringList("DELETE_EVENT_LIST");
572  count = 0;
573  }
574  }
575 
576  // make sure the last chunk is deleted
577  sendReceiveStringList(strList);
578 
579  // run zmaudit to clean up the orphaned db entries
580  strList = QStringList("RUN_ZMAUDIT");
581  sendReceiveStringList(strList);
582 }
583 
584 bool ZMClient::readData(unsigned char *data, int dataSize)
585 {
586  qint64 read = 0;
587  int errmsgtime = 0;
588  MythTimer timer;
589  timer.start();
590  int elapsed;
591 
592  while (dataSize > 0)
593  {
594  qint64 sret = m_socket->Read(
595  (char*) data + read, dataSize, 100 /*ms*/);
596  if (sret > 0)
597  {
598  read += sret;
599  dataSize -= sret;
600  if (dataSize > 0)
601  {
602  timer.start();
603  }
604  }
605  else if (sret < 0)
606  {
607  LOG(VB_GENERAL, LOG_ERR, "readData: Error, readBlock");
609  return false;
610  }
611  else if (!m_socket->IsConnected())
612  {
613  LOG(VB_GENERAL, LOG_ERR,
614  "readData: Error, socket went unconnected");
616  return false;
617  }
618  else
619  {
620  elapsed = timer.elapsed();
621  if (elapsed > 10000)
622  {
623  if ((elapsed - errmsgtime) > 10000)
624  {
625  errmsgtime = elapsed;
626  LOG(VB_GENERAL, LOG_ERR,
627  QString("m_socket->: Waiting for data: %1 %2")
628  .arg(read).arg(dataSize));
629  }
630  }
631 
632  if (elapsed > 100000)
633  {
634  LOG(VB_GENERAL, LOG_ERR, "Error, readData timeout (readBlock)");
635  return false;
636  }
637  }
638  }
639 
640  return true;
641 }
642 
643 void ZMClient::getEventFrame(Event *event, int frameNo, MythImage **image)
644 {
645  QMutexLocker locker(&m_commandLock);
646 
647  if (*image)
648  {
649  (*image)->DecrRef();
650  *image = nullptr;
651  }
652 
653  QStringList strList("GET_EVENT_FRAME");
654  strList << QString::number(event->monitorID());
655  strList << QString::number(event->eventID());
656  strList << QString::number(frameNo);
657  strList << event->startTime(Qt::LocalTime).toString("yy/MM/dd/hh/mm/ss");
658  if (!sendReceiveStringList(strList))
659  return;
660 
661  // sanity check
662  if (strList.size() < 2)
663  {
664  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
665  return;
666  }
667 
668  // get frame length from data
669  int imageSize = strList[1].toInt();
670 
671  // grab the image data
672  unsigned char *data = new unsigned char[imageSize];
673  if (!readData(data, imageSize))
674  {
675  LOG(VB_GENERAL, LOG_ERR,
676  "ZMClient::getEventFrame(): Failed to get image data");
677  delete [] data;
678  return;
679  }
680 
681  // get a MythImage
683 
684  // extract the image data and create a MythImage from it
685  if (!(*image)->loadFromData(data, imageSize, "JPEG"))
686  {
687  LOG(VB_GENERAL, LOG_ERR,
688  "ZMClient::getEventFrame(): Failed to load image from data");
689  }
690 
691  delete [] data;
692 }
693 
694 void ZMClient::getAnalyseFrame(Event *event, int frameNo, QImage &image)
695 {
696  QMutexLocker locker(&m_commandLock);
697 
698  QStringList strList("GET_ANALYSE_FRAME");
699  strList << QString::number(event->monitorID());
700  strList << QString::number(event->eventID());
701  strList << QString::number(frameNo);
702  strList << event->startTime(Qt::LocalTime).toString("yy/MM/dd/hh/mm/ss");
703  if (!sendReceiveStringList(strList))
704  {
705  image = QImage();
706  return;
707  }
708 
709  // sanity check
710  if (strList.size() < 2)
711  {
712  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
713  return;
714  }
715 
716  // get frame length from data
717  int imageSize = strList[1].toInt();
718 
719  // grab the image data
720  unsigned char *data = new unsigned char[imageSize];
721  if (!readData(data, imageSize))
722  {
723  LOG(VB_GENERAL, LOG_ERR,
724  "ZMClient::getAnalyseFrame(): Failed to get image data");
725  image = QImage();
726  }
727  else
728  {
729  // extract the image data and create a QImage from it
730  if (!image.loadFromData(data, imageSize, "JPEG"))
731  {
732  LOG(VB_GENERAL, LOG_ERR,
733  "ZMClient::getAnalyseFrame(): Failed to load image from data");
734  image = QImage();
735  }
736  }
737 
738  delete [] data;
739 }
740 
741 int ZMClient::getLiveFrame(int monitorID, QString &status, unsigned char* buffer, int bufferSize)
742 {
743  QMutexLocker locker(&m_commandLock);
744 
745  QStringList strList("GET_LIVE_FRAME");
746  strList << QString::number(monitorID);
747  if (!sendReceiveStringList(strList))
748  {
749  if (strList.empty())
750  {
751  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
752  return 0;
753  }
754 
755  // the server sends a "WARNING" message if there is no new
756  // frame available we can safely ignore it
757  if (strList[0].startsWith("WARNING"))
758  {
759  return 0;
760  }
761  status = strList[0];
762  return 0;
763  }
764 
765  // sanity check
766  if (strList.size() < 4)
767  {
768  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
769  return 0;
770  }
771 
772  // get status
773  status = strList[2];
774 
775  // get frame length from data
776  int imageSize = strList[3].toInt();
777 
778  if (bufferSize < imageSize)
779  {
780  LOG(VB_GENERAL, LOG_ERR,
781  "ZMClient::getLiveFrame(): Live frame buffer is too small!");
782  return 0;
783  }
784 
785  // read the frame data
786  if (imageSize == 0)
787  return 0;
788 
789  if (!readData(buffer, imageSize))
790  {
791  LOG(VB_GENERAL, LOG_ERR,
792  "ZMClient::getLiveFrame(): Failed to get image data");
793  return 0;
794  }
795 
796  return imageSize;
797 }
798 
799 void ZMClient::getCameraList(QStringList &cameraList)
800 {
801  QMutexLocker locker(&m_commandLock);
802 
803  cameraList.clear();
804 
805  QStringList strList("GET_CAMERA_LIST");
806  if (!sendReceiveStringList(strList))
807  return;
808 
809  // sanity check
810  if (strList.size() < 2)
811  {
812  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
813  return;
814  }
815 
816  bool bOK;
817  int cameraCount = strList[1].toInt(&bOK);
818  if (!bOK)
819  {
820  LOG(VB_GENERAL, LOG_ERR,
821  "ZMClient received bad int in getCameraList()");
822  return;
823  }
824 
825  // sanity check
826  if (strList.size() < cameraCount + 2)
827  {
828  LOG(VB_GENERAL, LOG_ERR, QString(
829  "ZMClient got a mismatch between the number of cameras (%1) and "
830  "the expected number of stringlist items (%2) in getCameraList()")
831  .arg(cameraCount).arg(strList.size()));
832  return;
833  }
834 
835  for (int x = 0; x < cameraCount; x++)
836  {
837  cameraList.append(strList[x + 2]);
838  }
839 }
840 
842 {
843  QMutexLocker locker(&m_listLock);
844  return m_monitorList.count();
845 }
846 
848 {
849  QMutexLocker locker(&m_listLock);
850 
851  if (pos < 0 || pos > m_monitorList.count() - 1)
852  return nullptr;
853 
854  return m_monitorList.at(pos);
855 }
856 
858 {
859  QMutexLocker locker(&m_listLock);
860 
861  if (m_monitorMap.contains(monID))
862  return m_monitorMap.find(monID).value();
863 
864  return nullptr;
865 }
866 
868 {
869  QMutexLocker clocker(&m_commandLock);
870  QMutexLocker locker(&m_listLock);
871 
872  for (int x = 0; x < m_monitorList.count(); x++)
873  delete m_monitorList.at(x);
874 
875  m_monitorList.clear();
876  m_monitorMap.clear();
877 
878  QStringList strList("GET_MONITOR_LIST");
879  if (!sendReceiveStringList(strList))
880  return;
881 
882  // sanity check
883  if (strList.size() < 2)
884  {
885  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
886  return;
887  }
888 
889  bool bOK;
890  int monitorCount = strList[1].toInt(&bOK);
891  if (!bOK)
892  {
893  LOG(VB_GENERAL, LOG_ERR,
894  "ZMClient received bad int in getMonitorList()");
895  return;
896  }
897 
898  // sanity check
899  if ((strList.size() - 2) / 5 != monitorCount)
900  {
901  LOG(VB_GENERAL, LOG_ERR,
902  "ZMClient got a mismatch between the number of monitors and "
903  "the expected number of stringlist items in getMonitorList()");
904  return;
905  }
906 
907  // get list of monitor id's that need monitoring
908  QString s = gCoreContext->GetSetting("ZoneMinderNotificationMonitors");
909  QStringList notificationMonitors = s.split(",");
910 
911  for (int x = 0; x < monitorCount; x++)
912  {
913  Monitor *item = new Monitor;
914  item->id = strList[x * 5 + 2].toInt();
915  item->name = strList[x * 5 + 3];
916  item->width = strList[x * 5 + 4].toInt();
917  item->height = strList[x * 5 + 5].toInt();
918  item->bytes_per_pixel = strList[x * 5 + 6].toInt();
919  item->zmcStatus = "";
920  item->zmaStatus = "";
921  item->events = 0;
922  item->status = "";
923  item->showNotifications = notificationMonitors.contains(QString::number(item->id));
924 
925  m_monitorList.append(item);
926  m_monitorMap.insert(item->id, item);
927 
928  LOG(VB_GENERAL, LOG_NOTICE,
929  QString("Monitor: %1 (%2) is using %3 bytes per pixel")
930  .arg(item->name).arg(item->id).arg(item->bytes_per_pixel));
931  }
932 }
933 
934 void ZMClient::setMonitorFunction(const int monitorID, const QString &function, const bool enabled)
935 {
936  QMutexLocker locker(&m_commandLock);
937 
938  QStringList strList("SET_MONITOR_FUNCTION");
939  strList << QString::number(monitorID);
940  strList << function;
941  strList << QString::number(static_cast<int>(enabled));
942 
943  if (!sendReceiveStringList(strList))
944  return;
945 }
946 
948 {
949  QString s;
950 
951  for (int x = 0; x < m_monitorList.count(); x++)
952  {
953  Monitor *mon = m_monitorList.at(x);
954  if (mon->showNotifications)
955  {
956  if (!s.isEmpty())
957  s += QString(",%1").arg(mon->id);
958  else
959  s = QString("%1").arg(mon->id);
960  }
961  }
962 
963  gCoreContext->SaveSetting("ZoneMinderNotificationMonitors", s);
964 }
965 
966 void ZMClient::customEvent (QEvent* event)
967 {
968  if (event->type() == MythEvent::MythEventMessage)
969  {
970  MythEvent *me = static_cast<MythEvent*>(event);
971 
972  if (!me)
973  return;
974 
975  if (me->Message().startsWith("ZONEMINDER_NOTIFICATION"))
976  {
977  QStringList list = me->Message().simplified().split(' ');
978 
979  if (list.size() < 2)
980  return;
981 
982  int monID = list[1].toInt();
983  showMiniPlayer(monID);
984  }
985  }
986 
987  QObject::customEvent(event);
988 }
989 
990 void ZMClient::showMiniPlayer(int monitorID)
991 {
992  if (!isMiniPlayerEnabled())
993  return;
994 
995  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
996 
997  ZMMiniPlayer *miniPlayer = new ZMMiniPlayer(popupStack);
998 
999  miniPlayer->setAlarmMonitor(monitorID);
1000 
1001  if (miniPlayer->Create())
1002  popupStack->AddScreen(miniPlayer);
1003 }
#define ZM_PROTOCOL_VERSION
Definition: zmclient.cpp:22
bool m_zmclientReady
Definition: zmclient.h:89
int height
Definition: zmdefines.h:123
QList< Monitor * > m_monitorList
Definition: zmclient.h:80
void customEvent(QEvent *event) override
Definition: zmclient.cpp:966
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
QMap< int, Monitor * > m_monitorMap
Definition: zmclient.h:81
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
void setMonitorFunction(const int monitorID, const QString &function, const bool enabled)
Definition: zmclient.cpp:934
Monitor * getMonitorAt(int pos)
Definition: zmclient.cpp:847
void SaveSetting(const QString &key, int newValue)
static Type MythEventMessage
Definition: mythevent.h:66
QString zmaStatus
Definition: zmdefines.h:118
void removeListener(QObject *listener)
Remove a listener to the observable.
void getEventDates(const QString &monitorName, bool oldestFirst, QStringList &dateList)
Definition: zmclient.cpp:455
uint m_port
Definition: zmclient.h:86
static ZMClient * m_zmclient
Definition: zmclient.h:23
MythScreenStack * GetStack(const QString &stackname)
void getFrameList(int eventID, vector< Frame * > *frameList)
Definition: zmclient.cpp:501
int Read(char *, int size, int max_wait_ms)
Definition: mythsocket.cpp:537
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void addListener(QObject *listener)
Add a listener to the observable.
Monitor * getMonitorByID(int monID)
Definition: zmclient.cpp:857
void getServerStatus(QString &status, QString &cpuStat, QString &diskStat)
Definition: zmclient.cpp:258
bool enabled
Definition: zmdefines.h:115
Definition: zmserver.h:68
void showMiniPlayer(int monitorID)
Definition: zmclient.cpp:990
bool readData(unsigned char *data, int dataSize)
Definition: zmclient.cpp:584
State
Definition: zmserver.h:62
bool isMiniPlayerEnabled(void)
Definition: zmclient.h:64
void deleteEventList(vector< Event * > *eventList)
Definition: zmclient.cpp:556
QTimer * m_retryTimer
Definition: zmclient.h:88
def read(device=None, features=[])
Definition: disc.py:35
QString m_hostname
Definition: zmclient.h:85
void DisconnectFromHost(void)
Definition: mythsocket.cpp:508
double delta
Definition: zmdefines.h:95
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
This class is used as a container for messages.
Definition: mythevent.h:16
ZMClient()
Definition: zmclient.cpp:26
int getMonitorCount(void)
Definition: zmclient.cpp:841
void getEventList(const QString &monitorName, bool oldestFirst, const QString &date, bool includeContinuous, vector< Event * > *eventList)
Definition: zmclient.cpp:400
State state
Definition: zmdefines.h:127
int id
Definition: zmdefines.h:111
QString status
Definition: zmdefines.h:121
QString function
Definition: zmdefines.h:114
int bytes_per_pixel
Definition: zmdefines.h:124
QString GetSetting(const QString &key, const QString &defaultval="")
bool m_bConnected
Definition: zmclient.h:87
static bool setupZMClient(void)
Definition: zmclient.cpp:45
State previousState
Definition: zmdefines.h:128
int width
Definition: zmdefines.h:122
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
QMutex m_listLock
Definition: zmclient.h:78
void updateMonitorStatus(void)
Definition: zmclient.cpp:278
void ShowNotificationError(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
convenience utility to display error message as notification
static ZMClient * get(void)
Definition: zmclient.cpp:38
void doGetMonitorList(void)
Definition: zmclient.cpp:867
void setAlarmMonitor(int monID)
Definition: zmminiplayer.h:22
QString zmcStatus
Definition: zmdefines.h:117
MythPainter * GetCurrentPainter()
void saveNotificationMonitors(void)
Definition: zmclient.cpp:947
bool connectToHost(const QString &hostname, unsigned int port)
Definition: zmclient.cpp:63
MythMainWindow * GetMythMainWindow(void)
int elapsed(void) const
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
int GetNumSetting(const QString &key, int defaultval=0)
int eventID(void) const
Definition: zmdefines.h:47
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
Definition: zmserver.h:66
bool ConnectToHost(const QString &hostname, quint16 port)
connect to host
Definition: mythsocket.cpp:384
Event details.
Definition: zmdefines.h:25
Definition: zmserver.h:64
bool IsConnected(void) const
Definition: mythsocket.cpp:561
void shutdown()
Definition: zmclient.cpp:231
void getAnalyseFrame(Event *event, int frameNo, QImage &image)
Definition: zmclient.cpp:694
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
QMutex m_commandLock
Definition: zmclient.h:79
bool SendReceiveStringList(QStringList &list, uint min_reply_length=0, uint timeoutMS=kLongTimeout)
Definition: mythsocket.cpp:336
QMutex m_socketLock
Definition: zmclient.h:84
Definition: zmserver.h:67
bool updateAlarmStates(void)
Definition: zmclient.cpp:349
void restartConnection(void)
Definition: zmclient.cpp:221
void getEventFrame(Event *event, int frameNo, MythImage **image)
Definition: zmclient.cpp:643
void getCameraList(QStringList &cameraList)
Definition: zmclient.cpp:799
QString type
Definition: zmdefines.h:94
bool sendReceiveStringList(QStringList &strList)
Definition: zmclient.cpp:125
const QString & Message() const
Definition: mythevent.h:58
void deleteEvent(int eventID)
Definition: zmclient.cpp:547
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
bool showNotifications
Definition: zmdefines.h:126
static QString stateToString(State state)
Definition: zmclient.cpp:321
int monitorID(void) const
Definition: zmdefines.h:45
Default UTC.
Definition: mythdate.h:14
QString name
Definition: zmdefines.h:112
MythSocket * m_socket
Definition: zmclient.h:83
int events
Definition: zmdefines.h:119
bool checkProtoVersion(void)
Definition: zmclient.cpp:181
MythNotificationCenter * GetNotificationCenter(void)
int getLiveFrame(int monitorID, QString &status, unsigned char *buffer, int bufferSize)
Definition: zmclient.cpp:741
bool Create(void) override