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 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
654  strList << event->startTime(Qt::LocalTime).toString("yy/MM/dd/hh/mm/ss");
655 #else
656  static const QTimeZone localtime(QTimeZone::LocalTime);
657  strList << event->startTime(localtime).toString("yy/MM/dd/hh/mm/ss");
658 #endif
659  if (!sendReceiveStringList(strList))
660  return;
661 
662  // sanity check
663  if (strList.size() < 2)
664  {
665  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
666  return;
667  }
668 
669  // get frame length from data
670  int imageSize = strList[1].toInt();
671 
672  // grab the image data
673  auto *data = new unsigned char[imageSize];
674  if (!readData(data, imageSize))
675  {
676  LOG(VB_GENERAL, LOG_ERR,
677  "ZMClient::getEventFrame(): Failed to get image data");
678  delete [] data;
679  return;
680  }
681 
682  // get a MythImage
684 
685  // extract the image data and create a MythImage from it
686  if (!(*image)->loadFromData(data, imageSize, "JPEG"))
687  {
688  LOG(VB_GENERAL, LOG_ERR,
689  "ZMClient::getEventFrame(): Failed to load image from data");
690  }
691 
692  delete [] data;
693 }
694 
695 void ZMClient::getAnalyseFrame(Event *event, int frameNo, QImage &image)
696 {
697  QMutexLocker locker(&m_commandLock);
698 
699  QStringList strList("GET_ANALYSE_FRAME");
700  strList << QString::number(event->monitorID());
701  strList << QString::number(event->eventID());
702  strList << QString::number(frameNo);
703 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
704  strList << event->startTime(Qt::LocalTime).toString("yy/MM/dd/hh/mm/ss");
705 #else
706  static const QTimeZone localtime(QTimeZone::LocalTime);
707  strList << event->startTime(localtime).toString("yy/MM/dd/hh/mm/ss");
708 #endif
709  if (!sendReceiveStringList(strList))
710  {
711  image = QImage();
712  return;
713  }
714 
715  // sanity check
716  if (strList.size() < 2)
717  {
718  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
719  return;
720  }
721 
722  // get frame length from data
723  int imageSize = strList[1].toInt();
724 
725  // grab the image data
726  auto *data = new unsigned char[imageSize];
727  if (!readData(data, imageSize))
728  {
729  LOG(VB_GENERAL, LOG_ERR,
730  "ZMClient::getAnalyseFrame(): Failed to get image data");
731  image = QImage();
732  }
733  else
734  {
735  // extract the image data and create a QImage from it
736  if (!image.loadFromData(data, imageSize, "JPEG"))
737  {
738  LOG(VB_GENERAL, LOG_ERR,
739  "ZMClient::getAnalyseFrame(): Failed to load image from data");
740  image = QImage();
741  }
742  }
743 
744  delete [] data;
745 }
746 
747 int ZMClient::getLiveFrame(int monitorID, QString &status, FrameData& buffer)
748 {
749  QMutexLocker locker(&m_commandLock);
750 
751  QStringList strList("GET_LIVE_FRAME");
752  strList << QString::number(monitorID);
753  if (!sendReceiveStringList(strList))
754  {
755  if (strList.empty())
756  {
757  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
758  return 0;
759  }
760 
761  // the server sends a "WARNING" message if there is no new
762  // frame available we can safely ignore it
763  if (strList[0].startsWith("WARNING"))
764  {
765  return 0;
766  }
767  status = strList[0];
768  return 0;
769  }
770 
771  // sanity check
772  if (strList.size() < 4)
773  {
774  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
775  return 0;
776  }
777 
778  // get status
779  status = strList[2];
780 
781  // get frame length from data
782  size_t imageSize = strList[3].toInt();
783 
784  if (buffer.size() < imageSize)
785  {
786  LOG(VB_GENERAL, LOG_ERR,
787  "ZMClient::getLiveFrame(): Live frame buffer is too small!");
788  return 0;
789  }
790 
791  // read the frame data
792  if (imageSize == 0)
793  return 0;
794 
795  if (!readData(buffer.data(), imageSize))
796  {
797  LOG(VB_GENERAL, LOG_ERR,
798  "ZMClient::getLiveFrame(): Failed to get image data");
799  return 0;
800  }
801 
802  return imageSize;
803 }
804 
805 void ZMClient::getCameraList(QStringList &cameraList)
806 {
807  QMutexLocker locker(&m_commandLock);
808 
809  cameraList.clear();
810 
811  QStringList strList("GET_CAMERA_LIST");
812  if (!sendReceiveStringList(strList))
813  return;
814 
815  // sanity check
816  if (strList.size() < 2)
817  {
818  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
819  return;
820  }
821 
822  bool bOK = false;
823  int cameraCount = strList[1].toInt(&bOK);
824  if (!bOK)
825  {
826  LOG(VB_GENERAL, LOG_ERR,
827  "ZMClient received bad int in getCameraList()");
828  return;
829  }
830 
831  // sanity check
832  if (strList.size() < cameraCount + 2)
833  {
834  LOG(VB_GENERAL, LOG_ERR, QString(
835  "ZMClient got a mismatch between the number of cameras (%1) and "
836  "the expected number of stringlist items (%2) in getCameraList()")
837  .arg(cameraCount).arg(strList.size()));
838  return;
839  }
840 
841  for (int x = 0; x < cameraCount; x++)
842  {
843  cameraList.append(strList[x + 2]);
844  }
845 }
846 
848 {
849  QMutexLocker locker(&m_listLock);
850  return m_monitorList.count();
851 }
852 
854 {
855  QMutexLocker locker(&m_listLock);
856 
857  if (pos < 0 || pos > m_monitorList.count() - 1)
858  return nullptr;
859 
860  return m_monitorList.at(pos);
861 }
862 
864 {
865  QMutexLocker locker(&m_listLock);
866 
867  if (m_monitorMap.contains(monID))
868  return m_monitorMap.find(monID).value();
869 
870  return nullptr;
871 }
872 
874 {
875  QMutexLocker clocker(&m_commandLock);
876  QMutexLocker locker(&m_listLock);
877 
878  for (int x = 0; x < m_monitorList.count(); x++)
879  delete m_monitorList.at(x);
880 
881  m_monitorList.clear();
882  m_monitorMap.clear();
883 
884  QStringList strList("GET_MONITOR_LIST");
885  if (!sendReceiveStringList(strList))
886  return;
887 
888  // sanity check
889  if (strList.size() < 2)
890  {
891  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
892  return;
893  }
894 
895  bool bOK = false;
896  int monitorCount = strList[1].toInt(&bOK);
897  if (!bOK)
898  {
899  LOG(VB_GENERAL, LOG_ERR,
900  "ZMClient received bad int in getMonitorList()");
901  return;
902  }
903 
904  // sanity check
905  if ((strList.size() - 2) / 5 != monitorCount)
906  {
907  LOG(VB_GENERAL, LOG_ERR,
908  "ZMClient got a mismatch between the number of monitors and "
909  "the expected number of stringlist items in getMonitorList()");
910  return;
911  }
912 
913  // get list of monitor id's that need monitoring
914  QString s = gCoreContext->GetSetting("ZoneMinderNotificationMonitors");
915  QStringList notificationMonitors = s.split(",");
916 
917  for (int x = 0; x < monitorCount; x++)
918  {
919  auto *item = new Monitor;
920  item->id = strList[(x * 5) + 2].toInt();
921  item->name = strList[(x * 5) + 3];
922  item->width = strList[(x * 5) + 4].toInt();
923  item->height = strList[(x * 5) + 5].toInt();
924  item->bytes_per_pixel = strList[(x * 5) + 6].toInt();
925  item->zmcStatus = "";
926  item->zmaStatus = "";
927  item->events = 0;
928  item->status = "";
929  item->showNotifications = notificationMonitors.contains(QString::number(item->id));
930 
931  m_monitorList.append(item);
932  m_monitorMap.insert(item->id, item);
933 
934  LOG(VB_GENERAL, LOG_NOTICE,
935  QString("Monitor: %1 (%2) is using %3 bytes per pixel")
936  .arg(item->name).arg(item->id).arg(item->bytes_per_pixel));
937  }
938 }
939 
940 void ZMClient::setMonitorFunction(const int monitorID, const QString &function, const bool enabled)
941 {
942  QMutexLocker locker(&m_commandLock);
943 
944  QStringList strList("SET_MONITOR_FUNCTION");
945  strList << QString::number(monitorID);
946  strList << function;
947  strList << QString::number(static_cast<int>(enabled));
948 
949  if (!sendReceiveStringList(strList))
950  return;
951 }
952 
954 {
955  QString s;
956 
957  for (int x = 0; x < m_monitorList.count(); x++)
958  {
959  Monitor *mon = m_monitorList.at(x);
960  if (mon->showNotifications)
961  {
962  if (!s.isEmpty())
963  s += QString(",%1").arg(mon->id);
964  else
965  s = QString("%1").arg(mon->id);
966  }
967  }
968 
969  gCoreContext->SaveSetting("ZoneMinderNotificationMonitors", s);
970 }
971 
972 void ZMClient::customEvent (QEvent* event)
973 {
974  if (event->type() == MythEvent::kMythEventMessage)
975  {
976  auto *me = dynamic_cast<MythEvent*>(event);
977  if (!me)
978  return;
979 
980  if (me->Message().startsWith("ZONEMINDER_NOTIFICATION"))
981  {
982  QStringList list = me->Message().simplified().split(' ');
983 
984  if (list.size() < 2)
985  return;
986 
987  int monID = list[1].toInt();
988  showMiniPlayer(monID);
989  }
990  }
991 
992  QObject::customEvent(event);
993 }
994 
995 void ZMClient::showMiniPlayer(int monitorID) const
996 {
997  if (!isMiniPlayerEnabled())
998  return;
999 
1000  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1001 
1002  auto *miniPlayer = new ZMMiniPlayer(popupStack);
1003 
1004  miniPlayer->setAlarmMonitor(monitorID);
1005 
1006  if (miniPlayer->Create())
1007  popupStack->AddScreen(miniPlayer);
1008 }
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:118
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
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:116
ZMClient::getServerStatus
void getServerStatus(QString &status, QString &cpuStat, QString &diskStat)
Definition: zmclient.cpp:256
ZMClient::getMonitorCount
int getMonitorCount(void)
Definition: zmclient.cpp:847
discid.disc.read
def read(device=None, features=[])
Definition: disc.py:35
Monitor::events
int events
Definition: zmdefines.h:123
MythPainter::GetFormatImage
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
Definition: mythpainter.cpp:525
Frame
Definition: zmdefines.h:102
ZMClient::ZMClient
ZMClient()
Definition: zmclient.cpp:25
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:132
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:863
ALERT
@ ALERT
Definition: zmserver.h:73
ZMClient::isMiniPlayerEnabled
bool isMiniPlayerEnabled(void) const
Definition: zmclient.h:67
Monitor::zmcStatus
QString zmcStatus
Definition: zmdefines.h:121
ZMMiniPlayer
Definition: zmminiplayer.h:11
MythMainWindow::GetPainter
MythPainter * GetPainter()
Definition: mythmainwindow.cpp:257
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
State
State
Definition: zmserver.h:68
Monitor::enabled
bool enabled
Definition: zmdefines.h:119
ZMClient::saveNotificationMonitors
void saveNotificationMonitors(void)
Definition: zmclient.cpp:953
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:27
ZMClient::getEventDates
void getEventDates(const QString &monitorName, bool oldestFirst, QStringList &dateList)
Definition: zmclient.cpp:453
ZMClient::restartConnection
void restartConnection(void)
Definition: zmclient.cpp:219
PREALARM
@ PREALARM
Definition: zmserver.h:71
IDLE
@ IDLE
Definition: zmserver.h:70
stateToString
static QString stateToString(State state)
Definition: zmclient.cpp:319
ALARM
@ ALARM
Definition: zmserver.h:72
ZMClient::m_bConnected
bool m_bConnected
Definition: zmclient.h:90
Monitor::showNotifications
bool showNotifications
Definition: zmdefines.h:130
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:695
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:873
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:916
zmminiplayer.h
Monitor::zmaStatus
QString zmaStatus
Definition: zmdefines.h:122
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
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:131
Frame::type
QString type
Definition: zmdefines.h:104
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:49
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
ZMClient::getCameraList
void getCameraList(QStringList &cameraList)
Definition: zmclient.cpp:805
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:995
GetNotificationCenter
MythNotificationCenter * GetNotificationCenter(void)
Definition: mythmainwindow.cpp:124
mythcontext.h
Event::monitorID
int monitorID(void) const
Definition: zmdefines.h:47
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
ZMClient::customEvent
void customEvent(QEvent *event) override
Definition: zmclient.cpp:972
ZMClient::~ZMClient
~ZMClient() override
Definition: zmclient.cpp:240
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:322
Monitor::id
int id
Definition: zmdefines.h:115
FrameData
std::array< uint8_t, MAX_IMAGE_SIZE > FrameData
Definition: zmserver.h:33
Monitor
Definition: zmdefines.h:108
ZMClient::getLiveFrame
int getLiveFrame(int monitorID, QString &status, FrameData &buffer)
Definition: zmclient.cpp:747
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:885
ZMClient::getMonitorAt
Monitor * getMonitorAt(int pos)
Definition: zmclient.cpp:853
ZMClient::setMonitorFunction
void setMonitorFunction(int monitorID, const QString &function, bool enabled)
Definition: zmclient.cpp:940
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:566
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:902
TAPE
@ TAPE
Definition: zmserver.h:74