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