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