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